Add a discussion about callbacks to API Conventions

Fixed: 437347302
Change-Id: Id4d8397b7e765ea112066f066a2bbad61bbab9e6
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/81167
Auto-Submit: David Benjamin <davidben@google.com>
Commit-Queue: Lily Chen <chlily@google.com>
Reviewed-by: Lily Chen <chlily@google.com>
diff --git a/API-CONVENTIONS.md b/API-CONVENTIONS.md
index 9885030..ba6206e 100644
--- a/API-CONVENTIONS.md
+++ b/API-CONVENTIONS.md
@@ -322,3 +322,132 @@
 particular objects. In general, stateless reference-counted objects like `RSA`
 or `EVP_PKEY` which represent keys may typically be used from multiple threads
 simultaneously, provided no thread mutates the key.
+
+
+## Callbacks and Closures
+
+Several BoringSSL APIs, particularly in libssl, allow applications to configure
+callbacks to customize behavior. Often, an application may wish to pass in some
+[closure](https://en.wikipedia.org/wiki/Closure_(computer_programming)), where
+the callback is bound to some additional state. For example, a callback for TLS
+private key offload may need a handle to the application-specific private key.
+
+BoringSSL's APIs are C-based and use C function pointers, which do not support
+bound variables. Instead, C callback APIs split the closure into a function
+pointer and some `void *` data parameter. This is sometimes called "arg",
+"callback data", "context", "data", or "user data".
+
+For example, the `SSL_CTX_set_cert_cb` function takes an `arg` parameter, which
+is passed back into the user-supplied callback, `cb`. The user would pass a
+function that casts `arg` back to the expected type and looks up bound data as
+needed:
+
+```
+OPENSSL_EXPORT void SSL_CTX_set_cert_cb(SSL_CTX *ctx,
+                                        int (*cb)(SSL *ssl, void *arg),
+                                        void *arg);
+```
+
+An application might use it with a C++ `std::function` as follows:
+
+```
+int RunCertCallback(SSL *ssl, void *arg) {
+  auto *f = static_cast<std::function<int(SSL*)>*>(arg);
+  return (*f)(ssl);
+}
+
+std::function<int(SSL*)> cert_cb = ...;
+SSL_CTX_set_cert_cb(ctx, RunCertCallback, &cert_cb);
+```
+
+Note that such an application would additionally need to ensure that `cert_cb`
+outlives `ctx`, e.g. by storing it in the `SSL_CTX`'s owning object.
+
+BoringSSL APIs, however, commonly take callbacks without an explicit data
+parameter. For example, the `SSL_set_custom_verify` takes an undecorated
+`callback` parameter:
+
+```
+OPENSSL_EXPORT void SSL_set_custom_verify(
+    SSL *ssl, int mode,
+    enum ssl_verify_result_t (*callback)(SSL *ssl, uint8_t *out_alert));
+```
+
+In such APIs, the callback is expected to look up data through the owning
+object, here the `ssl`. Many types in BoringSSL, including `SSL`, support
+`ex_data`. `ex_data` lets applications associate extra data with the object. See
+the [API documentation](https://commondatastorage.googleapis.com/chromium-boringssl-docs/ex_data.h.html)
+for more details. `ex_data` also supports registering a `free_func` callback,
+which can give the application more options to ensure callback data outlives the
+object.
+
+Often, for a callback-heavy object like `SSL`, the application will already have
+some owning object that wraps the `SSL`. The application can then register a
+single `ex_data` index, pointering back to the owning object, and store all the
+callback state there.
+
+For example, this code snippet connects `SSL` callbacks to methods on some
+wrapper `MySSLConnection` class.
+
+```
+class MySSLConnection {
+ private:
+  void Init() {
+    ssl_.reset(SSL_new(...));
+    // Save a pointer in `ssl_` back to `this`. `this` owns and thus outlives
+    // `ssl_`. (To have `ssl_` own its ex_data, use `SSL_get_ex_new_index`'s
+    // `free_func` parameter.)
+    CHECK(SSL_set_ex_data(ssl_.get(), ExDataIndex(), this));
+    // Register callbacks.
+    SSL_set_custom_verify(ssl_.get(), SSL_VERIFY_PEER,
+                          &MySSLConnection::DoVerifyCallback);
+    SSL_set_info_callback(ssl_.get(), &MySSLConnection::DoInfoCallback);
+    ...
+  }
+
+  static int ExDataIndex() {
+    static const int kIndex = [] {
+      int idx = SSL_get_ex_new_index(0, nullptr, nullptr, nullptr);
+      CHECK(idx >= 0);
+      return idx;
+    }();
+    return kIndex;
+  }
+
+  static MySSLConnection *FromSSL(const SSL *ssl) {
+    return static_cast<MySSLConnection*>(
+        SSL_get_ex_data(ssl_.get(), ExDataIndex()));
+  }
+
+  // Callback functions passed to BoringSSL:
+  static ssl_verify_result_t DoVerifyCallback(SSL *ssl, uint8_t *out_alert)) {
+    return FromSSL(ssl)->Verify(out_alert);
+  }
+  static void DoInfoCallback(const SSL *ssl, int type, int value) {
+    return FromSSL(ssl)->InfoCallback(type, value);
+  }
+
+  // The underlying methods that the callback functions forward to:
+  ssl_verify_result_t VerifyCallback(uint8_t *out_alert)) { ... }
+  void InfoCallback(int type, int value) { ... }
+
+  bssl::UniquePtr<SSL> ssl_;
+};
+```
+
+In other cases, the callback may live on a different object than is passed into
+the callback. The application can then use ex_data on either the passed-in
+object, or follow accessors to parent objects. For example, an `SSL_get_SSL_CTX`
+returns the `SSL_CTX` of an `SSL` and
+[`SSL_CTX_set_cert_verify_callback`'s documentation](https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_cert_verify_callback)
+mentions that `SSL_get_ex_data_X509_STORE_CTX_idx` may be used to find the `SSL`
+corresponding to the `X509_STORE_CTX`.
+
+```
+OPENSSL_EXPORT void SSL_CTX_sess_set_new_cb(
+    SSL_CTX *ctx, int (*new_session_cb)(SSL *ssl, SSL_SESSION *session));
+
+OPENSSL_EXPORT void SSL_CTX_set_cert_verify_callback(
+    SSL_CTX *ctx, int (*callback)(X509_STORE_CTX *store_ctx, void *arg),
+    void *arg);
+```