diff --git a/rust/examples/dhtnode.rs b/rust/examples/dhtnode.rs
index a4589d37960794bac4c047ef25597c3cc7c6993e..88505b5f8e15948caae7938e5cc25c7711f60593 100644
--- a/rust/examples/dhtnode.rs
+++ b/rust/examples/dhtnode.rs
@@ -3,7 +3,7 @@ use std::ffi::CString;
 use std::{thread, time};
 use libc::c_void;
 
-use opendht::*;
+use opendht::{InfoHash,DhtRunner,Value};
 
 extern fn get_cb(v: *mut Value, ptr: *mut c_void) {
     if ptr.is_null() {
@@ -15,6 +15,16 @@ extern fn get_cb(v: *mut Value, ptr: *mut c_void) {
     }
 }
 
+extern fn value_cb(v: *mut Value, expired: bool, ptr: *mut c_void) {
+    if ptr.is_null() {
+        return;
+    }
+    let _handler: &mut Handler = unsafe { &mut *(ptr as *mut Handler) };
+    unsafe {
+        println!("Got data: {} - expired: {}", *v, expired);
+    }
+}
+
 extern fn done_cb(ok: bool, ptr: *mut c_void) {
     let _handler: &mut Handler = unsafe { &mut *(ptr as *mut Handler) };
     println!("In done - {}", ok);
@@ -41,9 +51,15 @@ fn main() {
     let mut handler = Handler {
         _data: 8,
     };
+    let ptr = &mut handler as *mut _ as *mut c_void;
+
+    println!("Start listening /foo");
+    let token = dht.listen(&InfoHash::get("foo"), value_cb, ptr);
+    thread::sleep(ten_secs);
+    println!("Stop listening /foo");
+    dht.cancel_listen(&InfoHash::get("foo"), token);
     loop {
         println!("Get /alice");
-        let ptr = &mut handler as *mut _ as *mut c_void;
         dht.get(&InfoHash::get("alice"), get_cb, done_cb, ptr);
         let v = Value::new("hi!");
         dht.put(&InfoHash::get("bob"), Box::into_raw(v), done_cb, ptr);
diff --git a/rust/src/ffi.rs b/rust/src/ffi.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f4b7801e83840ee556b5506f3f5633dd386ae8bf
--- /dev/null
+++ b/rust/src/ffi.rs
@@ -0,0 +1,63 @@
+use libc::{c_char, c_void, in_port_t, size_t};
+
+const HASH_LEN: usize = 20;
+
+#[repr(C)]
+pub struct InfoHash
+{
+    pub d: [u8; HASH_LEN],
+}
+
+#[repr(C)]
+pub struct DhtRunner
+{
+    _opaque: [u8; 0]
+}
+
+#[repr(C)]
+pub struct Value
+{
+    _opaque: [u8; 0]
+}
+
+#[repr(C)]
+pub struct DataView
+{
+    pub data: *const u8,
+    pub size: size_t
+}
+
+
+#[repr(C)]
+pub struct OpToken
+{
+    _opaque: [u8; 0]
+}
+
+
+#[link(name = "opendht-c")]
+extern {
+    pub fn dht_infohash_print(h: *const InfoHash) -> *mut c_char;
+    pub fn dht_infohash_random(h: *mut InfoHash);
+    pub fn dht_infohash_get(h: *mut InfoHash, dat: *mut u8, dat_size: size_t);
+
+    pub fn dht_value_get_data(data: *const Value) -> DataView;
+    pub fn dht_value_unref(data: *mut Value);
+    pub fn dht_value_new(data: *const u8, size: size_t) -> *mut Value;
+
+    pub fn dht_runner_new() -> *mut DhtRunner;
+    pub fn dht_runner_delete(dht: *mut DhtRunner);
+    pub fn dht_runner_run(dht: *mut DhtRunner, port: in_port_t);
+    pub fn dht_runner_bootstrap(dht: *mut DhtRunner, host: *const c_char, service: *const c_char);
+    pub fn dht_runner_get(dht: *mut DhtRunner, h: *const InfoHash,
+                      get_cb: extern fn(*mut Value, *mut c_void),
+                      done_cb: extern fn(bool, *mut c_void),
+                      cb_user_data: *mut c_void);
+    pub fn dht_runner_put(dht: *mut DhtRunner, h: *const InfoHash, v: *const Value,
+                      done_cb: extern fn(bool, *mut c_void),
+                      cb_user_data: *mut c_void);
+    pub fn dht_runner_listen(dht: *mut DhtRunner, h: *const InfoHash,
+                      cb: extern fn(*mut Value, bool, *mut c_void),
+                      cb_user_data: *mut c_void) -> *const OpToken;
+    pub fn dht_runner_cancel_listen(dht: *mut DhtRunner, h: *const InfoHash, token: *const OpToken);
+}
\ No newline at end of file
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index b8bb46b58f787f891a764952eb5539d3203f0de7..a0274aac255736298303f31cd3ef933002cf07a4 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -1,62 +1,15 @@
 extern crate libc;
+
+mod ffi;
+use ffi::*;
+pub use ffi::{ DhtRunner, InfoHash, Value};
+
 use std::fmt;
 use std::ffi::CStr;
 use std::ffi::CString;
-use std::ptr;
 use std::str;
 use std::slice;
-use libc::{c_char, c_void, in_port_t, size_t, uint8_t};
-
-const HASH_LEN: usize = 20;
-
-#[repr(C)]
-pub struct InfoHash
-{
-    d: [u8; HASH_LEN],
-}
-
-#[repr(C)]
-pub struct DhtRunner
-{
-    _opaque: [u8; 0]
-}
-
-#[repr(C)]
-pub struct Value
-{
-    _opaque: [u8; 0]
-}
-
-#[repr(C)]
-pub struct DataView
-{
-    data: *const uint8_t,
-    size: size_t
-}
-
-
-#[link(name = "opendht-c")]
-extern {    
-    fn dht_infohash_print(h: *const InfoHash) -> *mut c_char;
-    fn dht_infohash_random(h: *mut InfoHash);
-    fn dht_infohash_get(h: *mut InfoHash, dat: *mut uint8_t, dat_size: size_t);
-
-    fn dht_value_get_data(data: *const Value) -> DataView;
-    fn dht_value_unref(data: *mut Value);
-    fn dht_value_new(data: *const uint8_t, size: size_t) -> *mut Value;
-
-    fn dht_runner_new() -> *mut DhtRunner;
-    fn dht_runner_delete(dht: *mut DhtRunner);
-    fn dht_runner_run(dht: *mut DhtRunner, port: in_port_t);
-    fn dht_runner_bootstrap(dht: *mut DhtRunner, host: *const c_char, service: *const c_char);
-    fn dht_runner_get(dht: *mut DhtRunner, h: *const InfoHash,
-                      get_cb: extern fn(*mut Value, *mut c_void),
-                      done_cb: extern fn(bool, *mut c_void),
-                      cb_user_data: *mut c_void);
-    fn dht_runner_put(dht: *mut DhtRunner, h: *const InfoHash, v: *const Value,
-                      done_cb: extern fn(bool, *mut c_void),
-                      cb_user_data: *mut c_void);
-}
+use libc::c_void;
 
 impl InfoHash {
     pub fn new() -> InfoHash {
@@ -118,7 +71,7 @@ impl DhtRunner {
                 get_cb: extern fn(*mut Value, *mut c_void),
                 done_cb: extern fn(bool, *mut c_void),
                 cb_user_data: *mut c_void) {
-        
+
         unsafe {
             dht_runner_get(&mut *self, h, get_cb, done_cb, cb_user_data)
         }
@@ -127,11 +80,26 @@ impl DhtRunner {
     pub fn put(&mut self, h: &InfoHash, v: *const Value,
                 done_cb: extern fn(bool, *mut c_void),
                 cb_user_data: *mut c_void) {
-        
+
         unsafe {
             dht_runner_put(&mut *self, h, v, done_cb, cb_user_data)
         }
     }
+
+    pub fn listen(&mut self, h: &InfoHash,
+                cb: extern fn(*mut Value, bool, *mut c_void),
+                cb_user_data: *mut c_void) -> *const OpToken {
+        unsafe {
+            dht_runner_listen(&mut *self, h, cb, cb_user_data)
+        }
+    }
+
+    pub fn cancel_listen(&mut self, h: &InfoHash, token: *const OpToken) {
+
+        unsafe {
+            dht_runner_cancel_listen(&mut *self, h, token)
+        }
+    }
 }
 
 impl Drop for DhtRunner {