Add per-call context pointer API
diff --git a/src/core/channel/context.h b/src/core/channel/context.h
new file mode 100644
index 0000000..e2e5e80
--- /dev/null
+++ b/src/core/channel/context.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * 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_INTERNAL_CORE_CHANNEL_CONTEXT_H
+#define GRPC_INTERNAL_CORE_CHANNEL_CONTEXT_H
+
+/* Call object context pointers */
+typedef enum {
+  GRPC_CONTEXT_SECURITY = 0,
+  GRPC_CONTEXT_TRACING,
+  GRPC_CONTEXT_COUNT
+} grpc_context_index;
+
+#endif
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index 1369216..6cd21a9 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -204,6 +204,9 @@
   /* Received call statuses from various sources */
   received_status status[STATUS_SOURCE_COUNT];
 
+  void *context[GRPC_CONTEXT_COUNT];
+  void (*destroy_context[GRPC_CONTEXT_COUNT])(void *);
+
   /* Deadline alarm - if have_alarm is non-zero */
   grpc_alarm alarm;
 
@@ -291,6 +294,7 @@
     initial_op.recv_state = &call->recv_state;
     initial_op.on_done_recv = call_on_done_recv;
     initial_op.recv_user_data = call;
+    initial_op.context = call->context;
     call->receiving = 1;
     GRPC_CALL_INTERNAL_REF(call, "receiving");
     initial_op_ptr = &initial_op;
@@ -343,6 +347,11 @@
   for (i = 0; i < c->send_initial_metadata_count; i++) {
     grpc_mdelem_unref(c->send_initial_metadata[i].md);
   }
+  for (i = 0; i < GRPC_CONTEXT_COUNT; i++) {
+    if (c->destroy_context[i]) {
+      c->destroy_context[i](c->context[i]);
+    }
+  }
   grpc_sopb_destroy(&c->send_ops);
   grpc_sopb_destroy(&c->recv_ops);
   grpc_bbq_destroy(&c->incoming_queue);
@@ -1016,6 +1025,7 @@
 static void execute_op(grpc_call *call, grpc_transport_op *op) {
   grpc_call_element *elem;
   elem = CALL_ELEM_FROM_CALL(call, 0);
+  op->context = call->context;
   elem->filter->start_transport_op(elem, op);
 }
 
@@ -1253,3 +1263,16 @@
   return grpc_call_start_ioreq_and_call_back(call, reqs, out, finish_batch,
                                              tag);
 }
+
+void grpc_call_context_set(grpc_call *call, grpc_context_index elem, void *value,
+                           void (*destroy)(void *value)) {
+  if (call->destroy_context[elem]) {
+    call->destroy_context[elem](value);
+  }
+  call->context[elem] = value;
+  call->destroy_context[elem] = destroy;
+}
+
+void *grpc_call_context_get(grpc_call *call, grpc_context_index elem) {
+  return call->context[elem];
+}
diff --git a/src/core/surface/call.h b/src/core/surface/call.h
index 2d4c7f6..18a77ba 100644
--- a/src/core/surface/call.h
+++ b/src/core/surface/call.h
@@ -35,6 +35,7 @@
 #define GRPC_INTERNAL_CORE_SURFACE_CALL_H
 
 #include "src/core/channel/channel_stack.h"
+#include "src/core/channel/context.h"
 #include <grpc/grpc.h>
 
 /* Primitive operation types - grpc_op's get rewritten into these */
@@ -120,6 +121,13 @@
                          grpc_call *call, const grpc_op *ops, size_t nops,
                          void *tag);
 
+/* Set a context pointer.
+   No thread safety guarantees are made wrt this value. */
+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_trace_batch) grpc_call_log_batch(sev, call, ops, nops, tag)
 
diff --git a/src/core/transport/transport.h b/src/core/transport/transport.h
index cdea0b9..7a389ea 100644
--- a/src/core/transport/transport.h
+++ b/src/core/transport/transport.h
@@ -76,6 +76,9 @@
 
   grpc_status_code cancel_with_status;
   grpc_mdstr *cancel_message;
+
+  /* Indexes correspond to grpc_context_index enum values */
+  void *const *context;
 } grpc_transport_op;
 
 /* Callbacks made from the transport to the upper layers of grpc. */