diff --git a/c/opendht.cpp b/c/opendht.cpp
index 88ebdb5242c2ee508924a1ad9c00877cfc6931da..84d0546ebb0f60c6bc9280c5cf8a8166c054418a 100644
--- a/c/opendht.cpp
+++ b/c/opendht.cpp
@@ -63,11 +63,12 @@ bool dht_publickey_check_signature(const dht_publickey* pk, const char* data, si
 
 dht_blob dht_publickey_encrypt(const dht_publickey* pk, const char* data, size_t data_size)
 {
+    auto rdata = new dht::Blob;
+    *rdata = reinterpret_cast<const dht::crypto::PublicKey*>(pk)->encrypt((const uint8_t*)data, data_size);
     dht_blob ret;
-    ret.ptr = new dht::Blob;
-    *reinterpret_cast<dht::Blob*>(ret.ptr) = reinterpret_cast<const dht::crypto::PublicKey*>(pk)->encrypt((const uint8_t*)data, data_size);
-    ret.data = reinterpret_cast<dht::Blob*>(ret.ptr)->data();
-    ret.data_length = reinterpret_cast<dht::Blob*>(ret.ptr)->size();
+    ret.data = rdata->data();
+    ret.data_length = rdata->size();
+    ret.ptr = rdata;
     return ret;
 }
 
@@ -103,6 +104,30 @@ void dht_runner_get(dht_runner* r, const dht_infohash* h, dht_get_cb cb, dht_don
     });
 }
 
+dht_op_token* dht_runner_listen(dht_runner* r, const dht_infohash* h, dht_value_cb cb, void* cb_user_data)
+{
+    auto runner = reinterpret_cast<dht::DhtRunner*>(r);
+    auto hash = reinterpret_cast<const dht::InfoHash*>(h);
+    auto fret = new std::future<size_t>;
+    *fret = runner->listen(*hash, [cb,cb_user_data](const std::vector<std::shared_ptr<dht::Value>>& values, bool expired) {
+        for (const auto& value : values) {
+            if (not cb(reinterpret_cast<dht_value*>(value.get()), expired, cb_user_data))
+                return false;
+        }
+        return true;
+    });
+    return (dht_op_token*)fret;
+}
+
+void
+dht_runner_cancel_listen(dht_runner* r, const dht_infohash* h, dht_op_token* t)
+{
+    auto runner = reinterpret_cast<dht::DhtRunner*>(r);
+    auto hash = reinterpret_cast<const dht::InfoHash*>(h);
+    auto token = reinterpret_cast<std::future<size_t>*>(t);
+    runner->cancelListen(*hash, std::move(*token));
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/c/opendht_c.h b/c/opendht_c.h
index c8a415f06c66f6ba7c147f6cdca9039ac5b688e7..b78b8b4db4a458d0353d1f8312c91e8a8edb5d0f 100644
--- a/c/opendht_c.h
+++ b/c/opendht_c.h
@@ -61,6 +61,10 @@ typedef bool (*dht_done_cb)(bool ok, void* user_data);
 typedef bool (*dht_shutdown_cb)(void* user_data);
 
 // dht::DhtRunner
+struct OPENDHT_C_PUBLIC dht_op_token;
+typedef struct dht_op_token dht_op_token;
+OPENDHT_C_PUBLIC void dht_op_token_delete(dht_op_token* token);
+
 struct OPENDHT_C_PUBLIC dht_runner;
 typedef struct dht_runner dht_runner;
 OPENDHT_C_PUBLIC dht_runner* dht_runner_new();
@@ -68,6 +72,8 @@ OPENDHT_C_PUBLIC void dht_runner_delete(dht_runner* runner);
 OPENDHT_C_PUBLIC void dht_runner_run(dht_runner* runner, in_port_t port);
 OPENDHT_C_PUBLIC void dht_runner_ping(dht_runner* runner, struct sockaddr* addr, socklen_t addr_len);
 OPENDHT_C_PUBLIC void dht_runner_get(dht_runner* runner, const dht_infohash* hash, dht_get_cb cb, dht_done_cb done_cb, void* cb_user_data);
+OPENDHT_C_PUBLIC dht_op_token* dht_runner_listen(dht_runner* runner, const dht_infohash* hash, dht_value_cb cb, void* cb_user_data);
+OPENDHT_C_PUBLIC void dht_runner_cancel_listen(dht_runner* runner, const dht_infohash* hash, dht_op_token* token);
 
 #ifdef __cplusplus
 }