added grpc extension library for C#
diff --git a/.gitignore b/.gitignore
index 6eb55b1..9c9ae5a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,6 +17,11 @@
 # python compiled objects
 *.pyc
 
+#eclipse project files
+.cproject
+.project
+.settings
+
 # cache for run_tests.py
 .run_tests_cache
 
diff --git a/Makefile b/Makefile
index 13f5129..122bcb4 100644
--- a/Makefile
+++ b/Makefile
@@ -553,13 +553,13 @@
 
 static: static_c static_cxx
 
-static_c:  libs/$(CONFIG)/libgpr.a libs/$(CONFIG)/libgrpc.a libs/$(CONFIG)/libgrpc_unsecure.a
+static_c:  libs/$(CONFIG)/libgpr.a libs/$(CONFIG)/libgrpc.a libs/$(CONFIG)/libgrpc_unsecure.a libs/$(CONFIG)/libgrpc_csharp_ext.a
 
 static_cxx:  libs/$(CONFIG)/libgrpc++.a
 
 shared: shared_c shared_cxx
 
-shared_c:  libs/$(CONFIG)/libgpr.$(SHARED_EXT) libs/$(CONFIG)/libgrpc.$(SHARED_EXT) libs/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT)
+shared_c:  libs/$(CONFIG)/libgpr.$(SHARED_EXT) libs/$(CONFIG)/libgrpc.$(SHARED_EXT) libs/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT) libs/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT)
 
 shared_cxx:  libs/$(CONFIG)/libgrpc++.$(SHARED_EXT)
 
@@ -1020,6 +1020,8 @@
 	$(Q) $(STRIP) libs/$(CONFIG)/libgrpc.a
 	$(E) "[STRIP]   Stripping libgrpc_unsecure.a"
 	$(Q) $(STRIP) libs/$(CONFIG)/libgrpc_unsecure.a
+	$(E) "[STRIP]   Stripping libgrpc_csharp_ext.a"
+	$(Q) $(STRIP) libs/$(CONFIG)/libgrpc_csharp_ext.a
 endif
 
 strip-static_cxx: static_cxx
@@ -1036,6 +1038,8 @@
 	$(Q) $(STRIP) libs/$(CONFIG)/libgrpc.$(SHARED_EXT)
 	$(E) "[STRIP]   Stripping libgrpc_unsecure.so"
 	$(Q) $(STRIP) libs/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT)
+	$(E) "[STRIP]   Stripping libgrpc_csharp_ext.so"
+	$(Q) $(STRIP) libs/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT)
 endif
 
 strip-shared_cxx: shared_cxx
@@ -1141,6 +1145,8 @@
 	$(Q) $(INSTALL) libs/$(CONFIG)/libgrpc.a $(prefix)/lib/libgrpc.a
 	$(E) "[INSTALL] Installing libgrpc_unsecure.a"
 	$(Q) $(INSTALL) libs/$(CONFIG)/libgrpc_unsecure.a $(prefix)/lib/libgrpc_unsecure.a
+	$(E) "[INSTALL] Installing libgrpc_csharp_ext.a"
+	$(Q) $(INSTALL) libs/$(CONFIG)/libgrpc_csharp_ext.a $(prefix)/lib/libgrpc_csharp_ext.a
 
 install-static_cxx: static_cxx strip-static_cxx
 	$(E) "[INSTALL] Installing libgrpc++.a"
@@ -1180,6 +1186,17 @@
 	$(Q) ln -sf libgrpc_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc_unsecure.so
 endif
 endif
+ifeq ($(SYSTEM),MINGW32)
+	$(E) "[INSTALL] Installing grpc_csharp_ext.$(SHARED_EXT)"
+	$(Q) $(INSTALL) libs/$(CONFIG)/grpc_csharp_ext.$(SHARED_EXT) $(prefix)/lib/grpc_csharp_ext.$(SHARED_EXT)
+	$(Q) $(INSTALL) libs/$(CONFIG)/libgrpc_csharp_ext-imp.a $(prefix)/lib/libgrpc_csharp_ext-imp.a
+else
+	$(E) "[INSTALL] Installing libgrpc_csharp_ext.$(SHARED_EXT)"
+	$(Q) $(INSTALL) libs/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT) $(prefix)/lib/libgrpc_csharp_ext.$(SHARED_EXT)
+ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf libgrpc_csharp_ext.$(SHARED_EXT) $(prefix)/lib/libgrpc_csharp_ext.so
+endif
+endif
 ifneq ($(SYSTEM),MINGW32)
 ifneq ($(SYSTEM),Darwin)
 	$(Q) ldconfig
@@ -2300,6 +2317,71 @@
 objs/$(CONFIG)/examples/tips/subscriber.o:     gens/examples/tips/label.pb.cc    gens/examples/tips/empty.pb.cc    gens/examples/tips/pubsub.pb.cc
 
 
+LIBGRPC_CSHARP_EXT_SRC = \
+    src/csharp/ext/grpc_csharp_ext.c \
+
+
+LIBGRPC_CSHARP_EXT_OBJS = $(addprefix objs/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_CSHARP_EXT_SRC))))
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure libraries if you don't have OpenSSL with ALPN.
+
+libs/$(CONFIG)/libgrpc_csharp_ext.a: openssl_dep_error
+
+ifeq ($(SYSTEM),MINGW32)
+libs/$(CONFIG)/grpc_csharp_ext.$(SHARED_EXT): openssl_dep_error
+else
+libs/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT): openssl_dep_error
+endif
+
+else
+
+ifneq ($(OPENSSL_DEP),)
+src/csharp/ext/grpc_csharp_ext.c: $(OPENSSL_DEP)
+endif
+
+libs/$(CONFIG)/libgrpc_csharp_ext.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBGRPC_CSHARP_EXT_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) rm -f libs/$(CONFIG)/libgrpc_csharp_ext.a
+	$(Q) $(AR) rcs libs/$(CONFIG)/libgrpc_csharp_ext.a $(LIBGRPC_CSHARP_EXT_OBJS)
+ifeq ($(SYSTEM),Darwin)
+	$(Q) ranlib libs/$(CONFIG)/libgrpc_csharp_ext.a 
+endif
+
+
+
+ifeq ($(SYSTEM),MINGW32)
+libs/$(CONFIG)/grpc_csharp_ext.$(SHARED_EXT): $(LIBGRPC_CSHARP_EXT_OBJS)  $(ZLIB_DEP)libs/$(CONFIG)/gpr.$(SHARED_EXT)libs/$(CONFIG)/grpc.$(SHARED_EXT) $(OPENSSL_DEP)
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) -Llibs/$(CONFIG) -shared -Wl,--output-def=libs/$(CONFIG)/grpc_csharp_ext.def -Wl,--out-implib=libs/$(CONFIG)/libgrpc_csharp_ext-imp.a -o libs/$(CONFIG)/grpc_csharp_ext.$(SHARED_EXT) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) $(LDLIBS_SECURE) $(OPENSSL_MERGE_LIBS) -lgpr-imp -lgrpc-imp
+else
+libs/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT): $(LIBGRPC_CSHARP_EXT_OBJS)  $(ZLIB_DEP) libs/$(CONFIG)/libgpr.$(SHARED_EXT) libs/$(CONFIG)/libgrpc.$(SHARED_EXT) $(OPENSSL_DEP)
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+ifeq ($(SYSTEM),Darwin)
+	$(Q) $(LD) $(LDFLAGS) -Llibs/$(CONFIG) -dynamiclib -o libs/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) $(LDLIBS_SECURE) $(OPENSSL_MERGE_LIBS) -lgpr -lgrpc
+else
+	$(Q) $(LD) $(LDFLAGS) -Llibs/$(CONFIG) -shared -Wl,-soname,libgrpc_csharp_ext.so.0 -o libs/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) $(LDLIBS_SECURE) $(OPENSSL_MERGE_LIBS) -lgpr -lgrpc
+	$(Q) ln -sf libgrpc_csharp_ext.$(SHARED_EXT) libs/$(CONFIG)/libgrpc_csharp_ext.so.0
+	$(Q) ln -sf libgrpc_csharp_ext.$(SHARED_EXT) libs/$(CONFIG)/libgrpc_csharp_ext.so
+endif
+endif
+
+
+endif
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(LIBGRPC_CSHARP_EXT_OBJS:.o=.dep)
+endif
+endif
+
+objs/$(CONFIG)/src/csharp/ext/grpc_csharp_ext.o: 
+
+
 LIBEND2END_FIXTURE_CHTTP2_FAKE_SECURITY_SRC = \
     test/core/end2end/fixtures/chttp2_fake_security.c \
 
diff --git a/build.json b/build.json
index 1cd8775..e7ab14b 100644
--- a/build.json
+++ b/build.json
@@ -441,6 +441,18 @@
         "grpc",
         "gpr"
       ]
+    },
+    {
+      "name": "grpc_csharp_ext",
+      "build": "all",
+      "language": "c",
+      "deps": [
+        "gpr",
+        "grpc"
+      ],
+      "src": [
+        "src/csharp/ext/grpc_csharp_ext.c"
+      ]
     }
   ],
   "targets": [
diff --git a/src/csharp/.gitignore b/src/csharp/.gitignore
new file mode 100644
index 0000000..dbf38f3
--- /dev/null
+++ b/src/csharp/.gitignore
@@ -0,0 +1,2 @@
+*.userprefs
+test-results
diff --git a/src/csharp/README.md b/src/csharp/README.md
new file mode 100755
index 0000000..dac5a45
--- /dev/null
+++ b/src/csharp/README.md
@@ -0,0 +1,22 @@
+gRPC C#
+=======
+
+A C# implementation of gRPC, Google's RPC library.
+
+EXPERIMENTAL ONLY
+-----------------
+
+**This gRPC C# implementation is work-in-progress and is not expected to work yet.**
+
+- The implementation is a wrapper around gRPC C core library
+- Code only runs under mono currently, because there have been issues building
+  the gRPC C core library under Windows.
+- It is very possible that some parts of the code will be heavily refactored or
+  completely rewritten.
+
+CONTENTS
+--------
+
+- ext:
+  The extension library that wraps C API to be more digestible by C#.
+
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
new file mode 100644
index 0000000..74d11c6
--- /dev/null
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -0,0 +1,113 @@
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice.h>
+
+#include <string.h>
+
+grpc_byte_buffer *string_to_byte_buffer(const char *buffer, size_t len) {
+  gpr_slice slice = gpr_slice_from_copied_buffer(buffer, len);
+  grpc_byte_buffer *bb = grpc_byte_buffer_create(&slice, 1);
+  gpr_slice_unref(slice);
+  return bb;
+}
+
+void grpc_call_start_write_from_copied_buffer(grpc_call *call,
+                                              const char *buffer, size_t len,
+                                              void *tag, gpr_uint32 flags) {
+  grpc_byte_buffer *byte_buffer = string_to_byte_buffer(buffer, len);
+  GPR_ASSERT(grpc_call_start_write_old(call, byte_buffer, tag, flags) ==
+             GRPC_CALL_OK);
+  grpc_byte_buffer_destroy(byte_buffer);
+}
+
+grpc_completion_type grpc_event_type(const grpc_event *event) {
+  return event->type;
+}
+
+grpc_op_error grpc_event_write_accepted(const grpc_event *event) {
+  GPR_ASSERT(event->type == GRPC_WRITE_ACCEPTED);
+  return event->data.invoke_accepted;
+}
+
+grpc_op_error grpc_event_finish_accepted(const grpc_event *event) {
+  GPR_ASSERT(event->type == GRPC_FINISH_ACCEPTED);
+  return event->data.finish_accepted;
+}
+
+grpc_status_code grpc_event_finished_status(const grpc_event *event) {
+  GPR_ASSERT(event->type == GRPC_FINISHED);
+  return event->data.finished.status;
+}
+
+const char *grpc_event_finished_details(const grpc_event *event) {
+  GPR_ASSERT(event->type == GRPC_FINISHED);
+  return event->data.finished.details;
+}
+
+gpr_intptr grpc_event_read_length(const grpc_event *event) {
+  GPR_ASSERT(event->type == GRPC_READ);
+  if (!event->data.read) {
+    return -1;
+  }
+  return grpc_byte_buffer_length(event->data.read);
+}
+
+/*
+ * Copies data from read event to a buffer. Fatal error occurs if
+ * buffer is too small.
+ */
+void grpc_event_read_copy_to_buffer(const grpc_event *event, char *buffer,
+                                    size_t buffer_len) {
+  grpc_byte_buffer_reader *reader;
+  gpr_slice slice;
+  size_t offset = 0;
+
+  GPR_ASSERT(event->type == GRPC_READ);
+  reader = grpc_byte_buffer_reader_create(event->data.read);
+
+  GPR_ASSERT(event->data.read);
+  while (grpc_byte_buffer_reader_next(reader, &slice)) {
+    size_t len = GPR_SLICE_LENGTH(slice);
+    GPR_ASSERT(offset + len <= buffer_len);
+    memcpy(buffer + offset, GPR_SLICE_START_PTR(slice),
+           GPR_SLICE_LENGTH(slice));
+    offset += len;
+    gpr_slice_unref(slice);
+  }
+  grpc_byte_buffer_reader_destroy(reader);
+}
+
+grpc_call *grpc_event_call(const grpc_event *event) {
+  /* we only allow this for newly incoming server calls. */
+  GPR_ASSERT(event->type == GRPC_SERVER_RPC_NEW);
+  return event->call;
+}
+
+const char *grpc_event_server_rpc_new_method(const grpc_event *event) {
+  GPR_ASSERT(event->type == GRPC_SERVER_RPC_NEW);
+  return event->data.server_rpc_new.method;
+}
+
+grpc_completion_type grpc_completion_queue_next_with_callback(
+    grpc_completion_queue *cq) {
+  grpc_event *ev;
+  grpc_completion_type t;
+  void (*callback)(grpc_event *);
+
+  ev = grpc_completion_queue_next(cq, gpr_inf_future);
+  t = ev->type;
+  if (ev->tag) {
+    /* call the callback in ev->tag */
+    /* C forbids to cast object pointers to function pointers, so
+     * we cast to intptr first.
+     */
+    callback = (void (*)(grpc_event *))(gpr_intptr)ev->tag;
+    (*callback)(ev);
+  }
+  grpc_event_finish(ev);
+
+  /* return completion type to allow some handling for events that have no
+   * tag - such as GRPC_QUEUE_SHUTDOWN
+   */
+  return t;
+}