+#ifndef OPENSSL_NO_TRACE
+static int trace_attach_cb(int category, int type, const void *data)
+{
+ switch (type) {
+ case 0: /* Channel */
+ OSSL_TRACE2(TRACE, "Attach channel %p to category '%s'\n",
+ data, trace_categories[category].name);
+ break;
+ case 1: /* Prefix */
+ OSSL_TRACE2(TRACE, "Attach prefix \"%s\" to category '%s'\n",
+ (const char *)data, trace_categories[category].name);
+ break;
+ case 2: /* Suffix */
+ OSSL_TRACE2(TRACE, "Attach suffix \"%s\" to category '%s'\n",
+ (const char *)data, trace_categories[category].name);
+ break;
+ default: /* No clue */
+ break;
+ }
+ return 1;
+}
+
+static int trace_detach_cb(int category, int type, const void *data)
+{
+ switch (type) {
+ case 0: /* Channel */
+ OSSL_TRACE2(TRACE, "Detach channel %p from category '%s'\n",
+ data, trace_categories[category].name);
+ break;
+ case 1: /* Prefix */
+ OSSL_TRACE2(TRACE, "Detach prefix \"%s\" from category '%s'\n",
+ (const char *)data, trace_categories[category].name);
+ break;
+ case 2: /* Suffix */
+ OSSL_TRACE2(TRACE, "Detach suffix \"%s\" from category '%s'\n",
+ (const char *)data, trace_categories[category].name);
+ break;
+ default: /* No clue */
+ break;
+ }
+ return 1;
+}
+
+static int set_trace_data(int category, BIO **channel,
+ const char **prefix, const char **suffix,
+ int (*attach_cb)(int, int, const void *),
+ int (*detach_cb)(int, int, const void *))
+{
+ BIO *curr_channel = trace_channels[category].bio;
+ char *curr_prefix = trace_channels[category].prefix;
+ char *curr_suffix = trace_channels[category].suffix;
+
+ /* Make sure to run the detach callback first on all data */
+ if (prefix != NULL && curr_prefix != NULL) {
+ detach_cb(category, 1, curr_prefix);
+ }
+
+ if (suffix != NULL && curr_suffix != NULL) {
+ detach_cb(category, 2, curr_suffix);
+ }
+
+ if (channel != NULL && curr_channel != NULL) {
+ detach_cb(category, 0, curr_channel);
+ }
+
+ /* After detach callbacks are done, clear data where appropriate */
+ if (prefix != NULL && curr_prefix != NULL) {
+ OPENSSL_free(curr_prefix);
+ trace_channels[category].prefix = NULL;
+ }
+
+ if (suffix != NULL && curr_suffix != NULL) {
+ OPENSSL_free(curr_suffix);
+ trace_channels[category].suffix = NULL;
+ }
+
+ if (channel != NULL && curr_channel != NULL) {
+ BIO_free(curr_channel);
+ trace_channels[category].bio = NULL;
+ }
+
+ /* Before running callbacks are done, set new data where appropriate */
+ if (channel != NULL && *channel != NULL) {
+ trace_channels[category].bio = *channel;
+ }
+
+ if (prefix != NULL && *prefix != NULL) {
+ if ((curr_prefix = OPENSSL_strdup(*prefix)) == NULL)
+ return 0;
+ trace_channels[category].prefix = curr_prefix;
+ }
+
+ if (suffix != NULL && *suffix != NULL) {
+ if ((curr_suffix = OPENSSL_strdup(*suffix)) == NULL)
+ return 0;
+ trace_channels[category].suffix = curr_suffix;
+ }
+
+ /* Finally, run the attach callback on the new data */
+ if (channel != NULL && *channel != NULL) {
+ attach_cb(category, 0, *channel);
+ }
+
+ if (prefix != NULL && *prefix != NULL) {
+ attach_cb(category, 1, *prefix);
+ }
+
+ if (suffix != NULL && *suffix != NULL) {
+ attach_cb(category, 2, *suffix);
+ }
+
+ return 1;
+}
+#endif
+