aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/include/gnunet_peerstore_plugin.h3
-rw-r--r--src/include/gnunet_peerstore_service.h23
-rw-r--r--src/peerstore/gnunet-service-peerstore.c39
-rw-r--r--src/peerstore/peerstore.h6
-rw-r--r--src/peerstore/peerstore_api.c3
-rw-r--r--src/peerstore/peerstore_common.c2
-rw-r--r--src/peerstore/peerstore_common.h1
-rw-r--r--src/peerstore/plugin_peerstore_sqlite.c85
-rw-r--r--src/peerstore/test_peerstore_api.c1
9 files changed, 126 insertions, 37 deletions
diff --git a/src/include/gnunet_peerstore_plugin.h b/src/include/gnunet_peerstore_plugin.h
index 18b3f690d..8eea796bb 100644
--- a/src/include/gnunet_peerstore_plugin.h
+++ b/src/include/gnunet_peerstore_plugin.h
@@ -68,7 +68,8 @@ struct GNUNET_PEERSTORE_PluginFunctions
68 const char *key, 68 const char *key,
69 const void *value, 69 const void *value,
70 size_t size, 70 size_t size,
71 struct GNUNET_TIME_Absolute expiry); 71 struct GNUNET_TIME_Absolute expiry,
72 enum GNUNET_PEERSTORE_StoreOption options);
72 73
73 /** 74 /**
74 * Iterate over the records given an optional peer id 75 * Iterate over the records given an optional peer id
diff --git a/src/include/gnunet_peerstore_service.h b/src/include/gnunet_peerstore_service.h
index acb7e0492..7a79a8b56 100644
--- a/src/include/gnunet_peerstore_service.h
+++ b/src/include/gnunet_peerstore_service.h
@@ -38,6 +38,25 @@ extern "C"
38#endif 38#endif
39 39
40/** 40/**
41 * Options for storing values in PEERSTORE
42 */
43enum GNUNET_PEERSTORE_StoreOption
44{
45
46 /**
47 * Possibly store multiple values under given key.
48 */
49 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
50
51 /**
52 * Delete any previous values for the given key before
53 * storing the given value.
54 */
55 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
56
57};
58
59/**
41 * Handle to the peerstore service. 60 * Handle to the peerstore service.
42 */ 61 */
43struct GNUNET_PEERSTORE_Handle; 62struct GNUNET_PEERSTORE_Handle;
@@ -130,7 +149,8 @@ GNUNET_PEERSTORE_disconnect(struct GNUNET_PEERSTORE_Handle *h);
130 * @param key entry key 149 * @param key entry key
131 * @param value entry value BLOB 150 * @param value entry value BLOB
132 * @param size size of 'value' 151 * @param size size of 'value'
133 * @param lifetime relative time after which the entry is (possibly) deleted 152 * @param expiry absolute time after which the entry is (possibly) deleted
153 * @param options store operation option
134 * @param cont Continuation function after the store request is processed 154 * @param cont Continuation function after the store request is processed
135 * @param cont_cls Closure for 'cont' 155 * @param cont_cls Closure for 'cont'
136 */ 156 */
@@ -142,6 +162,7 @@ GNUNET_PEERSTORE_store (struct GNUNET_PEERSTORE_Handle *h,
142 const void *value, 162 const void *value,
143 size_t size, 163 size_t size,
144 struct GNUNET_TIME_Absolute expiry, 164 struct GNUNET_TIME_Absolute expiry,
165 enum GNUNET_PEERSTORE_StoreOption options,
145 GNUNET_PEERSTORE_Continuation cont, 166 GNUNET_PEERSTORE_Continuation cont,
146 void *cont_cls); 167 void *cont_cls);
147 168
diff --git a/src/peerstore/gnunet-service-peerstore.c b/src/peerstore/gnunet-service-peerstore.c
index 5d3ea6bb1..418204850 100644
--- a/src/peerstore/gnunet-service-peerstore.c
+++ b/src/peerstore/gnunet-service-peerstore.c
@@ -30,24 +30,6 @@
30#include "peerstore_common.h" 30#include "peerstore_common.h"
31 31
32/** 32/**
33 * Context of a PEERSTORE watch
34 */
35struct WatchContext
36{
37
38 /**
39 * Hash of key of watched record
40 */
41 struct GNUNET_HashCode keyhash;
42
43 /**
44 * Client requested the watch
45 */
46 struct GNUNET_SERVER_Client *client;
47
48};
49
50/**
51 * Interval for expired records cleanup (in seconds) 33 * Interval for expired records cleanup (in seconds)
52 */ 34 */
53#define CLEANUP_INTERVAL 300 /* 5mins */ 35#define CLEANUP_INTERVAL 300 /* 5mins */
@@ -95,6 +77,7 @@ shutdown_task (void *cls,
95 } 77 }
96 GNUNET_SERVER_notification_context_destroy(nc); 78 GNUNET_SERVER_notification_context_destroy(nc);
97 GNUNET_CONTAINER_multihashmap_destroy(watchers); 79 GNUNET_CONTAINER_multihashmap_destroy(watchers);
80 watchers = NULL;
98 GNUNET_SCHEDULER_shutdown(); 81 GNUNET_SCHEDULER_shutdown();
99} 82}
100 83
@@ -123,7 +106,7 @@ cleanup_expired_records(void *cls,
123 * @param cls closuer, a 'struct GNUNET_PEERSTORE_Record *' 106 * @param cls closuer, a 'struct GNUNET_PEERSTORE_Record *'
124 * @param key hash of record key 107 * @param key hash of record key
125 * @param value the watcher client, a 'struct GNUNET_SERVER_Client *' 108 * @param value the watcher client, a 'struct GNUNET_SERVER_Client *'
126 * @return #GNUNET_YES to continue iterating 109 * @return #GNUNET_OK to continue iterating
127 */ 110 */
128int client_disconnect_it(void *cls, 111int client_disconnect_it(void *cls,
129 const struct GNUNET_HashCode *key, 112 const struct GNUNET_HashCode *key,
@@ -131,7 +114,7 @@ int client_disconnect_it(void *cls,
131{ 114{
132 if(cls == value) 115 if(cls == value)
133 GNUNET_CONTAINER_multihashmap_remove(watchers, key, value); 116 GNUNET_CONTAINER_multihashmap_remove(watchers, key, value);
134 return GNUNET_YES; 117 return GNUNET_OK;
135} 118}
136 119
137/** 120/**
@@ -146,8 +129,9 @@ handle_client_disconnect (void *cls,
146 * client) 129 * client)
147{ 130{
148 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "A client was disconnected, cleaning up.\n"); 131 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "A client was disconnected, cleaning up.\n");
149 GNUNET_CONTAINER_multihashmap_iterate(watchers, 132 if(NULL != watchers)
150 &client_disconnect_it, client); 133 GNUNET_CONTAINER_multihashmap_iterate(watchers,
134 &client_disconnect_it, client);
151} 135}
152 136
153/** 137/**
@@ -196,12 +180,6 @@ int watch_notifier_it(void *cls,
196 struct StoreRecordMessage *srm; 180 struct StoreRecordMessage *srm;
197 181
198 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found a watcher to update.\n"); 182 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found a watcher to update.\n");
199 if(NULL == client)
200 {
201 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Removing a dead client.\n");
202 GNUNET_CONTAINER_multihashmap_remove(watchers, key, client);
203 return GNUNET_YES;
204 }
205 srm = PEERSTORE_create_record_message(record->sub_system, 183 srm = PEERSTORE_create_record_message(record->sub_system,
206 record->peer, 184 record->peer,
207 record->key, 185 record->key,
@@ -335,6 +313,7 @@ void handle_store (void *cls,
335 const struct GNUNET_MessageHeader *message) 313 const struct GNUNET_MessageHeader *message)
336{ 314{
337 struct GNUNET_PEERSTORE_Record *record; 315 struct GNUNET_PEERSTORE_Record *record;
316 struct StoreRecordMessage *srm;
338 317
339 record = PEERSTORE_parse_record_message(message); 318 record = PEERSTORE_parse_record_message(message);
340 if(NULL == record) 319 if(NULL == record)
@@ -343,6 +322,7 @@ void handle_store (void *cls,
343 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR); 322 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
344 return; 323 return;
345 } 324 }
325 srm = (struct StoreRecordMessage *)message;
346 if(NULL == record->sub_system 326 if(NULL == record->sub_system
347 || NULL == record->peer 327 || NULL == record->peer
348 || NULL == record->key) 328 || NULL == record->key)
@@ -363,7 +343,8 @@ void handle_store (void *cls,
363 record->key, 343 record->key,
364 record->value, 344 record->value,
365 record->value_size, 345 record->value_size,
366 *record->expiry)) 346 *record->expiry,
347 srm->options))
367 { 348 {
368 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to store requested value, sqlite database error."); 349 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to store requested value, sqlite database error.");
369 PEERSTORE_destroy_record(record); 350 PEERSTORE_destroy_record(record);
diff --git a/src/peerstore/peerstore.h b/src/peerstore/peerstore.h
index 5adf9f363..5757f784e 100644
--- a/src/peerstore/peerstore.h
+++ b/src/peerstore/peerstore.h
@@ -75,6 +75,12 @@ struct StoreRecordMessage
75 */ 75 */
76 struct GNUNET_TIME_Absolute expiry; 76 struct GNUNET_TIME_Absolute expiry;
77 77
78 /**
79 * Options, needed only in case of a
80 * store operation
81 */
82 enum GNUNET_PEERSTORE_StoreOption options;
83
78}; 84};
79 85
80/** 86/**
diff --git a/src/peerstore/peerstore_api.c b/src/peerstore/peerstore_api.c
index 238c7be19..8797d7818 100644
--- a/src/peerstore/peerstore_api.c
+++ b/src/peerstore/peerstore_api.c
@@ -419,6 +419,7 @@ GNUNET_PEERSTORE_store (struct GNUNET_PEERSTORE_Handle *h,
419 const void *value, 419 const void *value,
420 size_t size, 420 size_t size,
421 struct GNUNET_TIME_Absolute expiry, 421 struct GNUNET_TIME_Absolute expiry,
422 enum GNUNET_PEERSTORE_StoreOption options,
422 GNUNET_PEERSTORE_Continuation cont, 423 GNUNET_PEERSTORE_Continuation cont,
423 void *cont_cls) 424 void *cont_cls)
424{ 425{
@@ -434,6 +435,7 @@ GNUNET_PEERSTORE_store (struct GNUNET_PEERSTORE_Handle *h,
434 value, 435 value,
435 size, 436 size,
436 &expiry, 437 &expiry,
438 options,
437 GNUNET_MESSAGE_TYPE_PEERSTORE_STORE); 439 GNUNET_MESSAGE_TYPE_PEERSTORE_STORE);
438 sc = GNUNET_new(struct GNUNET_PEERSTORE_StoreContext); 440 sc = GNUNET_new(struct GNUNET_PEERSTORE_StoreContext);
439 sc->ev = ev; 441 sc->ev = ev;
@@ -595,6 +597,7 @@ GNUNET_PEERSTORE_iterate (struct GNUNET_PEERSTORE_Handle *h,
595 NULL, 597 NULL,
596 0, 598 0,
597 NULL, 599 NULL,
600 0,
598 GNUNET_MESSAGE_TYPE_PEERSTORE_ITERATE); 601 GNUNET_MESSAGE_TYPE_PEERSTORE_ITERATE);
599 ic = GNUNET_new(struct GNUNET_PEERSTORE_IterateContext); 602 ic = GNUNET_new(struct GNUNET_PEERSTORE_IterateContext);
600 ic->callback = callback; 603 ic->callback = callback;
diff --git a/src/peerstore/peerstore_common.c b/src/peerstore/peerstore_common.c
index eeaa3144c..48c04010a 100644
--- a/src/peerstore/peerstore_common.c
+++ b/src/peerstore/peerstore_common.c
@@ -137,6 +137,7 @@ PEERSTORE_create_record_mq_envelope(const char *sub_system,
137 const void *value, 137 const void *value,
138 size_t value_size, 138 size_t value_size,
139 struct GNUNET_TIME_Absolute *expiry, 139 struct GNUNET_TIME_Absolute *expiry,
140 enum GNUNET_PEERSTORE_StoreOption options,
140 uint16_t msg_type) 141 uint16_t msg_type)
141{ 142{
142 struct StoreRecordMessage *srm; 143 struct StoreRecordMessage *srm;
@@ -168,6 +169,7 @@ PEERSTORE_create_record_mq_envelope(const char *sub_system,
168 } 169 }
169 srm->sub_system_size = htons(ss_size); 170 srm->sub_system_size = htons(ss_size);
170 srm->value_size = htons(value_size); 171 srm->value_size = htons(value_size);
172 srm->options = options;
171 dummy = &srm[1]; 173 dummy = &srm[1];
172 memcpy(dummy, sub_system, ss_size); 174 memcpy(dummy, sub_system, ss_size);
173 dummy += ss_size; 175 dummy += ss_size;
diff --git a/src/peerstore/peerstore_common.h b/src/peerstore/peerstore_common.h
index dae2b437b..297eb9fc0 100644
--- a/src/peerstore/peerstore_common.h
+++ b/src/peerstore/peerstore_common.h
@@ -76,6 +76,7 @@ PEERSTORE_create_record_mq_envelope(const char *sub_system,
76 const void *value, 76 const void *value,
77 size_t value_size, 77 size_t value_size,
78 struct GNUNET_TIME_Absolute *expiry, 78 struct GNUNET_TIME_Absolute *expiry,
79 enum GNUNET_PEERSTORE_StoreOption options,
79 uint16_t msg_type); 80 uint16_t msg_type);
80 81
81/** 82/**
diff --git a/src/peerstore/plugin_peerstore_sqlite.c b/src/peerstore/plugin_peerstore_sqlite.c
index 8705ce188..38e72df51 100644
--- a/src/peerstore/plugin_peerstore_sqlite.c
+++ b/src/peerstore/plugin_peerstore_sqlite.c
@@ -100,13 +100,58 @@ struct Plugin
100 sqlite3_stmt *select_peerstoredata_by_all; 100 sqlite3_stmt *select_peerstoredata_by_all;
101 101
102 /** 102 /**
103 * Precompiled SQL for deleting expired records from peerstoredata 103 * Precompiled SQL for deleting expired
104 * records from peerstoredata
104 */ 105 */
105 sqlite3_stmt *expire_peerstoredata; 106 sqlite3_stmt *expire_peerstoredata;
106 107
108 /**
109 * Precompiled SQL for deleting records
110 * with given key
111 */
112 sqlite3_stmt *delete_peerstoredata;
113
107}; 114};
108 115
109/** 116/**
117 * Delete records with the given key
118 *
119 * @param cls closure (internal context for the plugin)
120 * @param sub_system name of sub system
121 * @param peer Peer identity (can be NULL)
122 * @param key entry key string (can be NULL)
123 * @return number of deleted records
124 */
125static int
126peerstore_sqlite_delete_records(void *cls,
127 const char *sub_system,
128 const struct GNUNET_PeerIdentity *peer,
129 const char *key)
130{
131 struct Plugin *plugin = cls;
132 sqlite3_stmt *stmt = plugin->delete_peerstoredata;
133
134 if((SQLITE_OK != sqlite3_bind_text(stmt, 1, sub_system, strlen(sub_system) + 1, SQLITE_STATIC))
135 || (SQLITE_OK != sqlite3_bind_blob(stmt, 2, peer, sizeof(struct GNUNET_PeerIdentity), SQLITE_STATIC))
136 || (SQLITE_OK != sqlite3_bind_text(stmt, 3, key, strlen(key) + 1, SQLITE_STATIC)))
137 {
138 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind");
139 }
140 else if (SQLITE_DONE != sqlite3_step (stmt))
141 {
142 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
143 "sqlite3_step");
144 }
145 if (SQLITE_OK != sqlite3_reset (stmt))
146 {
147 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
148 "sqlite3_reset");
149 return 0;
150 }
151 return sqlite3_changes(plugin->dbh);
152}
153
154/**
110 * Delete expired records (expiry < now) 155 * Delete expired records (expiry < now)
111 * 156 *
112 * @param cls closure (internal context for the plugin) 157 * @param cls closure (internal context for the plugin)
@@ -120,7 +165,7 @@ peerstore_sqlite_expire_records(void *cls,
120 struct Plugin *plugin = cls; 165 struct Plugin *plugin = cls;
121 sqlite3_stmt *stmt = plugin->expire_peerstoredata; 166 sqlite3_stmt *stmt = plugin->expire_peerstoredata;
122 167
123 if(SQLITE_OK != sqlite3_bind_int64(stmt, 1, (sqlite3_int64)now.abs_value_us)) 168 if(SQLITE_OK != sqlite3_bind_int64(stmt, 1, (sqlite3_uint64)now.abs_value_us))
124 { 169 {
125 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind"); 170 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind");
126 } 171 }
@@ -254,16 +299,21 @@ peerstore_sqlite_store_record(void *cls,
254 const char *key, 299 const char *key,
255 const void *value, 300 const void *value,
256 size_t size, 301 size_t size,
257 struct GNUNET_TIME_Absolute expiry) 302 struct GNUNET_TIME_Absolute expiry,
303 enum GNUNET_PEERSTORE_StoreOption options)
258{ 304{
259 struct Plugin *plugin = cls; 305 struct Plugin *plugin = cls;
260 sqlite3_stmt *stmt = plugin->insert_peerstoredata; 306 sqlite3_stmt *stmt = plugin->insert_peerstoredata;
261 307
308 if(GNUNET_PEERSTORE_STOREOPTION_REPLACE == options)
309 {
310 peerstore_sqlite_delete_records(cls, sub_system, peer, key);
311 }
262 if(SQLITE_OK != sqlite3_bind_text(stmt, 1, sub_system, strlen(sub_system) + 1, SQLITE_STATIC) 312 if(SQLITE_OK != sqlite3_bind_text(stmt, 1, sub_system, strlen(sub_system) + 1, SQLITE_STATIC)
263 || SQLITE_OK != sqlite3_bind_blob(stmt, 2, peer, sizeof(struct GNUNET_PeerIdentity), SQLITE_STATIC) 313 || SQLITE_OK != sqlite3_bind_blob(stmt, 2, peer, sizeof(struct GNUNET_PeerIdentity), SQLITE_STATIC)
264 || SQLITE_OK != sqlite3_bind_text(stmt, 3, key, strlen(key) + 1, SQLITE_STATIC) 314 || SQLITE_OK != sqlite3_bind_text(stmt, 3, key, strlen(key) + 1, SQLITE_STATIC)
265 || SQLITE_OK != sqlite3_bind_blob(stmt, 4, value, size, SQLITE_STATIC) 315 || SQLITE_OK != sqlite3_bind_blob(stmt, 4, value, size, SQLITE_STATIC)
266 || SQLITE_OK != sqlite3_bind_int64(stmt, 5, (sqlite3_int64)expiry.abs_value_us)) 316 || SQLITE_OK != sqlite3_bind_int64(stmt, 5, (sqlite3_uint64)expiry.abs_value_us))
267 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 317 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
268 "sqlite3_bind"); 318 "sqlite3_bind");
269 else if (SQLITE_DONE != sqlite3_step (stmt)) 319 else if (SQLITE_DONE != sqlite3_step (stmt))
@@ -330,6 +380,21 @@ sql_prepare (sqlite3 *dbh, const char *sql, sqlite3_stmt **stmt)
330} 380}
331 381
332/** 382/**
383 * sqlite3 custom function for comparison of uint64_t values
384 * since it is not supported by default
385 */
386void sqlite3_lessthan(sqlite3_context* ctx, int dummy,
387 sqlite3_value** values)
388{
389 uint64_t v1;
390 uint64_t v2;
391
392 v1 = (uint64_t)sqlite3_value_int64(values[0]);
393 v2 = (uint64_t)sqlite3_value_int64(values[1]);
394 sqlite3_result_int(ctx, v1 < v2);
395}
396
397/**
333 * Initialize the database connections and associated 398 * Initialize the database connections and associated
334 * data structures (create tables and indices 399 * data structures (create tables and indices
335 * as needed as well). 400 * as needed as well).
@@ -389,9 +454,11 @@ database_setup (struct Plugin *plugin)
389 " peer_id BLOB NOT NULL,\n" 454 " peer_id BLOB NOT NULL,\n"
390 " key TEXT NOT NULL,\n" 455 " key TEXT NOT NULL,\n"
391 " value BLOB NULL,\n" 456 " value BLOB NULL,\n"
392 " expiry INTEGER NOT NULL" 457 " expiry sqlite3_uint64 NOT NULL"
393 ");"); 458 ");");
394 459
460 sqlite3_create_function(plugin->dbh, "UINT64_LT", 2, SQLITE_UTF8, NULL, &sqlite3_lessthan, NULL, NULL);
461
395 /* Prepare statements */ 462 /* Prepare statements */
396 463
397 sql_prepare (plugin->dbh, 464 sql_prepare (plugin->dbh,
@@ -419,8 +486,14 @@ database_setup (struct Plugin *plugin)
419 &plugin->select_peerstoredata_by_all); 486 &plugin->select_peerstoredata_by_all);
420 sql_prepare(plugin->dbh, 487 sql_prepare(plugin->dbh,
421 "DELETE FROM peerstoredata" 488 "DELETE FROM peerstoredata"
422 " WHERE expiry < ?", 489 " WHERE UINT64_LT(expiry, ?)",
423 &plugin->expire_peerstoredata); 490 &plugin->expire_peerstoredata);
491 sql_prepare(plugin->dbh,
492 "DELETE FROM peerstoredata"
493 " WHERE sub_system = ?"
494 " AND peer_id = ?"
495 " AND key = ?",
496 &plugin->delete_peerstoredata);
424 497
425 return GNUNET_OK; 498 return GNUNET_OK;
426} 499}
diff --git a/src/peerstore/test_peerstore_api.c b/src/peerstore/test_peerstore_api.c
index 968467231..e4f6225c6 100644
--- a/src/peerstore/test_peerstore_api.c
+++ b/src/peerstore/test_peerstore_api.c
@@ -125,6 +125,7 @@ run (void *cls,
125 val, 125 val,
126 val_size, 126 val_size,
127 expiry, 127 expiry,
128 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
128 &store_cont, 129 &store_cont,
129 NULL); 130 NULL);
130} 131}