diff options
Diffstat (limited to 'src/namestore/gnunet-service-namestore.c')
-rw-r--r-- | src/namestore/gnunet-service-namestore.c | 396 |
1 files changed, 352 insertions, 44 deletions
diff --git a/src/namestore/gnunet-service-namestore.c b/src/namestore/gnunet-service-namestore.c index 9b2d9b6f3..d735822fb 100644 --- a/src/namestore/gnunet-service-namestore.c +++ b/src/namestore/gnunet-service-namestore.c | |||
@@ -121,6 +121,23 @@ struct ZoneIteration | |||
121 | int send_end; | 121 | int send_end; |
122 | }; | 122 | }; |
123 | 123 | ||
124 | /** | ||
125 | * Lock on a record set | ||
126 | */ | ||
127 | struct RecordsLock | ||
128 | { | ||
129 | /* DLL */ | ||
130 | struct RecordsLock *prev; | ||
131 | |||
132 | /* DLL */ | ||
133 | struct RecordsLock *next; | ||
134 | |||
135 | /* Hash of the locked label */ | ||
136 | struct GNUNET_HashCode label_hash; | ||
137 | |||
138 | /* Client locking the zone */ | ||
139 | struct NamestoreClient *client; | ||
140 | }; | ||
124 | 141 | ||
125 | /** | 142 | /** |
126 | * A namestore client | 143 | * A namestore client |
@@ -394,6 +411,16 @@ static struct StoreActivity *sa_head; | |||
394 | static struct StoreActivity *sa_tail; | 411 | static struct StoreActivity *sa_tail; |
395 | 412 | ||
396 | /** | 413 | /** |
414 | * Head of the DLL of record set locks | ||
415 | */ | ||
416 | static struct RecordsLock *locks_head; | ||
417 | |||
418 | /** | ||
419 | * Tail of the DLL of record set locks | ||
420 | */ | ||
421 | static struct RecordsLock *locks_tail; | ||
422 | |||
423 | /** | ||
397 | * Notification context shared by all monitors. | 424 | * Notification context shared by all monitors. |
398 | */ | 425 | */ |
399 | static struct GNUNET_NotificationContext *monitor_nc; | 426 | static struct GNUNET_NotificationContext *monitor_nc; |
@@ -420,6 +447,7 @@ static void | |||
420 | cleanup_task (void *cls) | 447 | cleanup_task (void *cls) |
421 | { | 448 | { |
422 | struct CacheOperation *cop; | 449 | struct CacheOperation *cop; |
450 | struct RecordsLock *lock; | ||
423 | 451 | ||
424 | (void) cls; | 452 | (void) cls; |
425 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping namestore service\n"); | 453 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping namestore service\n"); |
@@ -431,6 +459,14 @@ cleanup_task (void *cls) | |||
431 | GNUNET_CONTAINER_DLL_remove (cop_head, cop_tail, cop); | 459 | GNUNET_CONTAINER_DLL_remove (cop_head, cop_tail, cop); |
432 | GNUNET_free (cop); | 460 | GNUNET_free (cop); |
433 | } | 461 | } |
462 | while (NULL != (lock = locks_head)) | ||
463 | { | ||
464 | GNUNET_CONTAINER_DLL_remove (locks_head, | ||
465 | locks_tail, | ||
466 | lock); | ||
467 | GNUNET_free (lock); | ||
468 | } | ||
469 | |||
434 | if (NULL != namecache) | 470 | if (NULL != namecache) |
435 | { | 471 | { |
436 | GNUNET_NAMECACHE_disconnect (namecache); | 472 | GNUNET_NAMECACHE_disconnect (namecache); |
@@ -808,7 +844,8 @@ send_lookup_response (struct NamestoreClient *nc, | |||
808 | * @param rid client's request ID | 844 | * @param rid client's request ID |
809 | */ | 845 | */ |
810 | static void | 846 | static void |
811 | send_store_response (struct NamestoreClient *nc, int res, uint32_t rid) | 847 | send_store_response (struct NamestoreClient *nc, int res, const char*emsg, |
848 | uint32_t rid) | ||
812 | { | 849 | { |
813 | struct GNUNET_MQ_Envelope *env; | 850 | struct GNUNET_MQ_Envelope *env; |
814 | struct RecordStoreResponseMessage *rcr_msg; | 851 | struct RecordStoreResponseMessage *rcr_msg; |
@@ -820,10 +857,17 @@ send_store_response (struct NamestoreClient *nc, int res, uint32_t rid) | |||
820 | "Store requests completed", | 857 | "Store requests completed", |
821 | 1, | 858 | 1, |
822 | GNUNET_NO); | 859 | GNUNET_NO); |
823 | env = GNUNET_MQ_msg (rcr_msg, | 860 | env = GNUNET_MQ_msg_extra (rcr_msg, |
824 | GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE); | 861 | (NULL != emsg) ? strlen (emsg) + 1 : 0, |
862 | GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE); | ||
825 | rcr_msg->gns_header.r_id = htonl (rid); | 863 | rcr_msg->gns_header.r_id = htonl (rid); |
826 | rcr_msg->op_result = htonl (res); | 864 | rcr_msg->op_result = htonl (res); |
865 | rcr_msg->reserved = htons (0); | ||
866 | if (NULL != emsg) | ||
867 | { | ||
868 | rcr_msg->emsg_len = htons (strlen (emsg) + 1); | ||
869 | memcpy (&rcr_msg[1], emsg, strlen (emsg) + 1); | ||
870 | } | ||
827 | GNUNET_MQ_send (nc->mq, env); | 871 | GNUNET_MQ_send (nc->mq, env); |
828 | } | 872 | } |
829 | 873 | ||
@@ -874,7 +918,7 @@ finish_cache_operation (void *cls, int32_t success, const char *emsg) | |||
874 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CACHE operation completed\n"); | 918 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CACHE operation completed\n"); |
875 | GNUNET_CONTAINER_DLL_remove (cop_head, cop_tail, cop); | 919 | GNUNET_CONTAINER_DLL_remove (cop_head, cop_tail, cop); |
876 | if (NULL != cop->nc) | 920 | if (NULL != cop->nc) |
877 | send_store_response (cop->nc, success, cop->rid); | 921 | send_store_response (cop->nc, success, emsg, cop->rid); |
878 | if (NULL != (zi = cop->zi)) | 922 | if (NULL != (zi = cop->zi)) |
879 | { | 923 | { |
880 | zi->cache_ops--; | 924 | zi->cache_ops--; |
@@ -910,29 +954,40 @@ refresh_block (struct NamestoreClient *nc, | |||
910 | const struct GNUNET_GNSRECORD_Data *rd) | 954 | const struct GNUNET_GNSRECORD_Data *rd) |
911 | { | 955 | { |
912 | struct GNUNET_GNSRECORD_Block *block; | 956 | struct GNUNET_GNSRECORD_Block *block; |
957 | struct GNUNET_GNSRECORD_Data rd_clean[rd_count]; | ||
913 | struct CacheOperation *cop; | 958 | struct CacheOperation *cop; |
914 | struct GNUNET_IDENTITY_PublicKey pkey; | 959 | struct GNUNET_IDENTITY_PublicKey pkey; |
915 | struct GNUNET_GNSRECORD_Data *nick; | 960 | struct GNUNET_GNSRECORD_Data *nick; |
916 | struct GNUNET_GNSRECORD_Data *res; | 961 | struct GNUNET_GNSRECORD_Data *res; |
917 | unsigned int res_count; | 962 | unsigned int res_count; |
963 | unsigned int rd_count_clean; | ||
918 | struct GNUNET_TIME_Absolute exp_time; | 964 | struct GNUNET_TIME_Absolute exp_time; |
919 | 965 | ||
966 | /** Do not block-cache tombstones */ | ||
967 | rd_count_clean = 0; | ||
968 | for (int i = 0; i < rd_count; i++) | ||
969 | { | ||
970 | if (GNUNET_GNSRECORD_TYPE_TOMBSTONE == rd[i].record_type) | ||
971 | continue; | ||
972 | rd_clean[rd_count_clean++] = rd[i]; | ||
973 | } | ||
974 | |||
920 | nick = get_nick_record (zone_key); | 975 | nick = get_nick_record (zone_key); |
921 | res_count = rd_count; | 976 | res_count = rd_count_clean; |
922 | res = (struct GNUNET_GNSRECORD_Data *) rd; /* fixme: a bit unclean... */ | 977 | res = (struct GNUNET_GNSRECORD_Data *) rd_clean; /* fixme: a bit unclean... */ |
923 | if ((NULL != nick) && (0 != strcmp (name, GNUNET_GNS_EMPTY_LABEL_AT))) | 978 | if ((NULL != nick) && (0 != strcmp (name, GNUNET_GNS_EMPTY_LABEL_AT))) |
924 | { | 979 | { |
925 | nick->flags = | 980 | nick->flags = |
926 | (nick->flags | GNUNET_GNSRECORD_RF_PRIVATE) ^ GNUNET_GNSRECORD_RF_PRIVATE; | 981 | (nick->flags | GNUNET_GNSRECORD_RF_PRIVATE) ^ GNUNET_GNSRECORD_RF_PRIVATE; |
927 | merge_with_nick_records (nick, rd_count, rd, &res_count, &res); | 982 | merge_with_nick_records (nick, rd_count_clean, rd_clean, &res_count, &res); |
928 | } | 983 | } |
929 | if (NULL != nick) | 984 | if (NULL != nick) |
930 | GNUNET_free (nick); | 985 | GNUNET_free (nick); |
931 | if (0 == res_count) | 986 | if (0 == res_count) |
932 | { | 987 | { |
933 | if (NULL != nc) | 988 | if (NULL != nc) |
934 | send_store_response (nc, GNUNET_OK, rid); | 989 | send_store_response (nc, GNUNET_OK, NULL, rid); |
935 | if (rd != res) | 990 | if (rd_clean != res) |
936 | GNUNET_free (res); | 991 | GNUNET_free (res); |
937 | return; /* no data, no need to update cache */ | 992 | return; /* no data, no need to update cache */ |
938 | } | 993 | } |
@@ -943,20 +998,21 @@ refresh_block (struct NamestoreClient *nc, | |||
943 | 1, | 998 | 1, |
944 | GNUNET_NO); | 999 | GNUNET_NO); |
945 | if (NULL != nc) | 1000 | if (NULL != nc) |
946 | send_store_response (nc, GNUNET_OK, rid); | 1001 | send_store_response (nc, GNUNET_OK, NULL, rid); |
947 | if (rd != res) | 1002 | if (rd_clean != res) |
948 | GNUNET_free (res); | 1003 | GNUNET_free (res); |
949 | return; | 1004 | return; |
950 | } | 1005 | } |
951 | exp_time = GNUNET_GNSRECORD_record_get_expiration_time (res_count, res); | 1006 | exp_time = GNUNET_GNSRECORD_record_get_expiration_time (res_count, res, |
1007 | GNUNET_TIME_UNIT_ZERO_ABS); | ||
952 | if (cache_keys) | 1008 | if (cache_keys) |
953 | GNUNET_assert (GNUNET_OK == | 1009 | GNUNET_assert (GNUNET_OK == |
954 | GNUNET_GNSRECORD_block_create2 (zone_key, exp_time, name, | 1010 | GNUNET_GNSRECORD_block_create2 (zone_key, exp_time, name, |
955 | res, res_count, &block)); | 1011 | res, res_count, &block)); |
956 | else | 1012 | else |
957 | GNUNET_assert (GNUNET_OK == | 1013 | GNUNET_assert (GNUNET_OK == |
958 | GNUNET_GNSRECORD_block_create (zone_key, exp_time, name, | 1014 | GNUNET_GNSRECORD_block_create (zone_key, exp_time, name, |
959 | res, res_count, &block)); | 1015 | res, res_count, &block)); |
960 | GNUNET_assert (NULL != block); | 1016 | GNUNET_assert (NULL != block); |
961 | GNUNET_IDENTITY_key_get_public (zone_key, &pkey); | 1017 | GNUNET_IDENTITY_key_get_public (zone_key, &pkey); |
962 | GNUNET_log ( | 1018 | GNUNET_log ( |
@@ -974,7 +1030,7 @@ refresh_block (struct NamestoreClient *nc, | |||
974 | cop->nc = nc; | 1030 | cop->nc = nc; |
975 | cop->zi = zi; | 1031 | cop->zi = zi; |
976 | if (NULL != zi) | 1032 | if (NULL != zi) |
977 | zi->cache_ops++; | 1033 | zi->cache_ops ++; |
978 | cop->rid = rid; | 1034 | cop->rid = rid; |
979 | GNUNET_CONTAINER_DLL_insert (cop_head, cop_tail, cop); | 1035 | GNUNET_CONTAINER_DLL_insert (cop_head, cop_tail, cop); |
980 | cop->qe = GNUNET_NAMECACHE_block_cache (namecache, | 1036 | cop->qe = GNUNET_NAMECACHE_block_cache (namecache, |
@@ -982,7 +1038,7 @@ refresh_block (struct NamestoreClient *nc, | |||
982 | &finish_cache_operation, | 1038 | &finish_cache_operation, |
983 | cop); | 1039 | cop); |
984 | GNUNET_free (block); | 1040 | GNUNET_free (block); |
985 | if (rd != res) | 1041 | if (rd_clean != res) |
986 | GNUNET_free (res); | 1042 | GNUNET_free (res); |
987 | } | 1043 | } |
988 | 1044 | ||
@@ -1098,6 +1154,7 @@ client_disconnect_cb (void *cls, | |||
1098 | struct NamestoreClient *nc = app_ctx; | 1154 | struct NamestoreClient *nc = app_ctx; |
1099 | struct ZoneIteration *no; | 1155 | struct ZoneIteration *no; |
1100 | struct CacheOperation *cop; | 1156 | struct CacheOperation *cop; |
1157 | struct RecordsLock *lock; | ||
1101 | 1158 | ||
1102 | (void) cls; | 1159 | (void) cls; |
1103 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected\n", client); | 1160 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected\n", client); |
@@ -1148,6 +1205,15 @@ client_disconnect_cb (void *cls, | |||
1148 | for (cop = cop_head; NULL != cop; cop = cop->next) | 1205 | for (cop = cop_head; NULL != cop; cop = cop->next) |
1149 | if (nc == cop->nc) | 1206 | if (nc == cop->nc) |
1150 | cop->nc = NULL; | 1207 | cop->nc = NULL; |
1208 | for (lock = locks_head; NULL != lock; lock = lock->next) | ||
1209 | { | ||
1210 | if (nc != lock->client) | ||
1211 | continue; | ||
1212 | GNUNET_CONTAINER_DLL_remove (locks_head, | ||
1213 | locks_tail, | ||
1214 | lock); | ||
1215 | GNUNET_free (lock); | ||
1216 | } | ||
1151 | GNUNET_free (nc); | 1217 | GNUNET_free (nc); |
1152 | } | 1218 | } |
1153 | 1219 | ||
@@ -1341,6 +1407,105 @@ check_record_lookup (void *cls, const struct LabelLookupMessage *ll_msg) | |||
1341 | return GNUNET_OK; | 1407 | return GNUNET_OK; |
1342 | } | 1408 | } |
1343 | 1409 | ||
1410 | static void | ||
1411 | calculate_lock_hash (const char *label, | ||
1412 | const struct GNUNET_IDENTITY_PrivateKey *zone, | ||
1413 | struct GNUNET_HashCode *result) | ||
1414 | { | ||
1415 | struct GNUNET_HashContext *hctx; | ||
1416 | |||
1417 | hctx = GNUNET_CRYPTO_hash_context_start (); | ||
1418 | GNUNET_CRYPTO_hash_context_read (hctx, label, strlen (label)); | ||
1419 | GNUNET_CRYPTO_hash_context_read (hctx, zone, | ||
1420 | sizeof (*zone)); | ||
1421 | GNUNET_CRYPTO_hash_context_finish (hctx, result); | ||
1422 | } | ||
1423 | |||
1424 | /** | ||
1425 | * Release a lock on a record set. | ||
1426 | * Does nothing if lock not held. | ||
1427 | * | ||
1428 | * @param label the label of the record set | ||
1429 | * @param zone the zone | ||
1430 | * @param nc the client releasing the lock | ||
1431 | */ | ||
1432 | static void | ||
1433 | NST_label_lock_release (const char *label, | ||
1434 | const struct GNUNET_IDENTITY_PrivateKey *zone, | ||
1435 | const struct NamestoreClient *nc) | ||
1436 | { | ||
1437 | struct GNUNET_HashCode label_hash; | ||
1438 | struct RecordsLock *lock; | ||
1439 | |||
1440 | calculate_lock_hash (label, zone, &label_hash); | ||
1441 | for (lock = locks_head; NULL != lock; lock = lock->next) | ||
1442 | if (0 == memcmp (&label_hash, &lock->label_hash, sizeof (label_hash))) | ||
1443 | break; | ||
1444 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1445 | "Record locked: %s\n", (NULL == lock) ? "No" : "Yes"); | ||
1446 | if (NULL == lock) | ||
1447 | return; | ||
1448 | if (lock->client != nc) | ||
1449 | { | ||
1450 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1451 | "Lock is held by other client on `%s'\n", label); | ||
1452 | return; | ||
1453 | } | ||
1454 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1455 | "Unocking %s\n", GNUNET_h2s (&label_hash)); | ||
1456 | GNUNET_CONTAINER_DLL_remove (locks_head, | ||
1457 | locks_tail, | ||
1458 | lock); | ||
1459 | GNUNET_free (lock); | ||
1460 | } | ||
1461 | |||
1462 | /** | ||
1463 | * Get/set a lock on a record set. | ||
1464 | * May be called multiple times but will | ||
1465 | * not aquire additional locks. | ||
1466 | * | ||
1467 | * @param the label of the record set | ||
1468 | * @param the zone | ||
1469 | * @param the client doing the locking | ||
1470 | * @return GNUNET_YES if lock retrieved or set already. | ||
1471 | */ | ||
1472 | static enum GNUNET_GenericReturnValue | ||
1473 | NST_label_lock (const char *label, | ||
1474 | const struct GNUNET_IDENTITY_PrivateKey *zone, | ||
1475 | struct NamestoreClient *nc) | ||
1476 | { | ||
1477 | struct GNUNET_HashCode label_hash; | ||
1478 | struct RecordsLock *lock; | ||
1479 | |||
1480 | calculate_lock_hash (label, zone, &label_hash); | ||
1481 | for (lock = locks_head; NULL != lock; lock = lock->next) | ||
1482 | if (0 == memcmp (&label_hash, &lock->label_hash, sizeof (label_hash))) | ||
1483 | break; | ||
1484 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1485 | "Record locked: %s\n", (NULL == lock) ? "No" : "Yes"); | ||
1486 | if (NULL != lock) | ||
1487 | { | ||
1488 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1489 | "Client holds lock: %s\n", (lock->client != nc) ? "No" : "Yes"); | ||
1490 | if (lock->client != nc) | ||
1491 | { | ||
1492 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1493 | "Lock is held by other client on `%s'\n", label); | ||
1494 | return GNUNET_NO; | ||
1495 | } | ||
1496 | return GNUNET_YES; | ||
1497 | } | ||
1498 | lock = GNUNET_new (struct RecordsLock); | ||
1499 | lock->client = nc; | ||
1500 | memcpy (&lock->label_hash, &label_hash, sizeof (label_hash)); | ||
1501 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1502 | "Locking %s\n", GNUNET_h2s (&label_hash)); | ||
1503 | GNUNET_CONTAINER_DLL_insert (locks_head, | ||
1504 | locks_tail, | ||
1505 | lock); | ||
1506 | return GNUNET_YES; | ||
1507 | } | ||
1508 | |||
1344 | 1509 | ||
1345 | /** | 1510 | /** |
1346 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP message | 1511 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP message |
@@ -1355,13 +1520,14 @@ handle_record_lookup (void *cls, const struct LabelLookupMessage *ll_msg) | |||
1355 | struct GNUNET_MQ_Envelope *env; | 1520 | struct GNUNET_MQ_Envelope *env; |
1356 | struct LabelLookupResponseMessage *llr_msg; | 1521 | struct LabelLookupResponseMessage *llr_msg; |
1357 | struct RecordLookupContext rlc; | 1522 | struct RecordLookupContext rlc; |
1523 | struct RecordsLock *lock; | ||
1524 | struct GNUNET_HashCode label_hash; | ||
1358 | const char *name_tmp; | 1525 | const char *name_tmp; |
1359 | char *res_name; | 1526 | char *res_name; |
1360 | char *conv_name; | 1527 | char *conv_name; |
1361 | uint32_t name_len; | 1528 | uint32_t name_len; |
1362 | int res; | 1529 | int res; |
1363 | 1530 | ||
1364 | name_len = ntohl (ll_msg->label_len); | ||
1365 | name_tmp = (const char *) &ll_msg[1]; | 1531 | name_tmp = (const char *) &ll_msg[1]; |
1366 | GNUNET_SERVICE_client_continue (nc->client); | 1532 | GNUNET_SERVICE_client_continue (nc->client); |
1367 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1533 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
@@ -1377,6 +1543,29 @@ handle_record_lookup (void *cls, const struct LabelLookupMessage *ll_msg) | |||
1377 | GNUNET_SERVICE_client_drop (nc->client); | 1543 | GNUNET_SERVICE_client_drop (nc->client); |
1378 | return; | 1544 | return; |
1379 | } | 1545 | } |
1546 | name_len = strlen (conv_name) + 1; | ||
1547 | if (GNUNET_YES == ntohl (ll_msg->locking)) | ||
1548 | { | ||
1549 | if (GNUNET_NO == NST_label_lock (conv_name, &ll_msg->zone, nc)) | ||
1550 | { | ||
1551 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1552 | "Lock is held by other client on `%s'\n", conv_name); | ||
1553 | env = | ||
1554 | GNUNET_MQ_msg_extra (llr_msg, | ||
1555 | name_len, | ||
1556 | GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP_RESPONSE); | ||
1557 | llr_msg->gns_header.r_id = ll_msg->gns_header.r_id; | ||
1558 | llr_msg->private_key = ll_msg->zone; | ||
1559 | llr_msg->name_len = htons (name_len); | ||
1560 | llr_msg->rd_count = htons (0); | ||
1561 | llr_msg->rd_len = htons (0); | ||
1562 | llr_msg->found = htons (GNUNET_SYSERR); | ||
1563 | GNUNET_memcpy (&llr_msg[1], conv_name, name_len); | ||
1564 | GNUNET_MQ_send (nc->mq, env); | ||
1565 | GNUNET_free (conv_name); | ||
1566 | return; | ||
1567 | } | ||
1568 | } | ||
1380 | rlc.label = conv_name; | 1569 | rlc.label = conv_name; |
1381 | rlc.found = GNUNET_NO; | 1570 | rlc.found = GNUNET_NO; |
1382 | rlc.res_rd_count = 0; | 1571 | rlc.res_rd_count = 0; |
@@ -1388,7 +1577,6 @@ handle_record_lookup (void *cls, const struct LabelLookupMessage *ll_msg) | |||
1388 | conv_name, | 1577 | conv_name, |
1389 | &lookup_it, | 1578 | &lookup_it, |
1390 | &rlc); | 1579 | &rlc); |
1391 | GNUNET_free (conv_name); | ||
1392 | env = | 1580 | env = |
1393 | GNUNET_MQ_msg_extra (llr_msg, | 1581 | GNUNET_MQ_msg_extra (llr_msg, |
1394 | name_len + rlc.rd_ser_len, | 1582 | name_len + rlc.rd_ser_len, |
@@ -1400,16 +1588,18 @@ handle_record_lookup (void *cls, const struct LabelLookupMessage *ll_msg) | |||
1400 | llr_msg->rd_len = htons (rlc.rd_ser_len); | 1588 | llr_msg->rd_len = htons (rlc.rd_ser_len); |
1401 | res_name = (char *) &llr_msg[1]; | 1589 | res_name = (char *) &llr_msg[1]; |
1402 | if ((GNUNET_YES == rlc.found) && (GNUNET_OK == res)) | 1590 | if ((GNUNET_YES == rlc.found) && (GNUNET_OK == res)) |
1403 | llr_msg->found = ntohs (GNUNET_YES); | 1591 | llr_msg->found = htons (GNUNET_YES); |
1404 | else | 1592 | else |
1405 | llr_msg->found = ntohs (GNUNET_NO); | 1593 | llr_msg->found = htons (GNUNET_NO); |
1406 | GNUNET_memcpy (&llr_msg[1], name_tmp, name_len); | 1594 | GNUNET_memcpy (&llr_msg[1], conv_name, name_len); |
1407 | GNUNET_memcpy (&res_name[name_len], rlc.res_rd, rlc.rd_ser_len); | 1595 | GNUNET_memcpy (&res_name[name_len], rlc.res_rd, rlc.rd_ser_len); |
1408 | GNUNET_MQ_send (nc->mq, env); | 1596 | GNUNET_MQ_send (nc->mq, env); |
1409 | GNUNET_free (rlc.res_rd); | 1597 | GNUNET_free (rlc.res_rd); |
1598 | GNUNET_free (conv_name); | ||
1410 | } | 1599 | } |
1411 | 1600 | ||
1412 | 1601 | ||
1602 | |||
1413 | /** | 1603 | /** |
1414 | * Checks a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE message | 1604 | * Checks a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE message |
1415 | * | 1605 | * |
@@ -1452,6 +1642,45 @@ check_record_store (void *cls, const struct RecordStoreMessage *rp_msg) | |||
1452 | 1642 | ||
1453 | 1643 | ||
1454 | /** | 1644 | /** |
1645 | * Check if set contains a tombstone, store if necessary | ||
1646 | * | ||
1647 | * @param cls a `struct GNUNET_GNSRECORD_Data **` for storing the nick (if found) | ||
1648 | * @param seq sequence number of the record, MUST NOT BE ZERO | ||
1649 | * @param private_key the private key of the zone (unused) | ||
1650 | * @param label should be #GNUNET_GNS_EMPTY_LABEL_AT | ||
1651 | * @param rd_count number of records in @a rd | ||
1652 | * @param rd records stored under @a label in the zone | ||
1653 | */ | ||
1654 | static void | ||
1655 | get_block_exp_existing (void *cls, | ||
1656 | uint64_t seq, | ||
1657 | const struct | ||
1658 | GNUNET_IDENTITY_PrivateKey *private_key, | ||
1659 | const char *label, | ||
1660 | unsigned int rd_count, | ||
1661 | const struct GNUNET_GNSRECORD_Data *rd) | ||
1662 | { | ||
1663 | struct GNUNET_TIME_Absolute *exp = cls; | ||
1664 | struct GNUNET_GNSRECORD_Data rd_pub[rd_count]; | ||
1665 | unsigned int rd_pub_count; | ||
1666 | char *emsg; | ||
1667 | |||
1668 | if (GNUNET_OK != GNUNET_GNSRECORD_convert_records_for_export (label, | ||
1669 | rd, | ||
1670 | rd_count, | ||
1671 | rd_pub, | ||
1672 | &rd_pub_count, | ||
1673 | exp, | ||
1674 | &emsg)) | ||
1675 | { | ||
1676 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1677 | "%s\n", emsg); | ||
1678 | GNUNET_free (emsg); | ||
1679 | } | ||
1680 | } | ||
1681 | |||
1682 | |||
1683 | /** | ||
1455 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE message | 1684 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE message |
1456 | * | 1685 | * |
1457 | * @param cls client sending the message | 1686 | * @param cls client sending the message |
@@ -1470,37 +1699,75 @@ handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg) | |||
1470 | unsigned int rd_count; | 1699 | unsigned int rd_count; |
1471 | int res; | 1700 | int res; |
1472 | struct StoreActivity *sa; | 1701 | struct StoreActivity *sa; |
1702 | struct RecordsLock *lock; | ||
1703 | struct GNUNET_HashCode label_hash; | ||
1704 | struct GNUNET_TIME_Absolute existing_block_exp; | ||
1705 | struct GNUNET_TIME_Absolute new_block_exp; | ||
1473 | 1706 | ||
1474 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1707 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1475 | "Received NAMESTORE_RECORD_STORE message\n"); | 1708 | "Received NAMESTORE_RECORD_STORE message\n"); |
1709 | existing_block_exp = GNUNET_TIME_UNIT_ZERO_ABS; | ||
1710 | new_block_exp = GNUNET_TIME_UNIT_ZERO_ABS; | ||
1476 | rid = ntohl (rp_msg->gns_header.r_id); | 1711 | rid = ntohl (rp_msg->gns_header.r_id); |
1477 | name_len = ntohs (rp_msg->name_len); | 1712 | name_len = ntohs (rp_msg->name_len); |
1478 | rd_count = ntohs (rp_msg->rd_count); | 1713 | rd_count = ntohs (rp_msg->rd_count); |
1479 | rd_ser_len = ntohs (rp_msg->rd_len); | 1714 | rd_ser_len = ntohs (rp_msg->rd_len); |
1480 | GNUNET_break (0 == ntohs (rp_msg->reserved)); | ||
1481 | name_tmp = (const char *) &rp_msg[1]; | 1715 | name_tmp = (const char *) &rp_msg[1]; |
1482 | rd_ser = &name_tmp[name_len]; | 1716 | rd_ser = &name_tmp[name_len]; |
1483 | { | 1717 | { |
1484 | struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)]; | 1718 | struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)]; |
1485 | 1719 | char *emsg; | |
1486 | if (GNUNET_OK != | ||
1487 | GNUNET_GNSRECORD_records_deserialize (rd_ser_len, rd_ser, rd_count, rd)) | ||
1488 | { | ||
1489 | GNUNET_break (0); | ||
1490 | GNUNET_SERVICE_client_drop (nc->client); | ||
1491 | return; | ||
1492 | } | ||
1493 | 1720 | ||
1494 | /* Extracting and converting private key */ | 1721 | /* Extracting and converting private key */ |
1495 | conv_name = GNUNET_GNSRECORD_string_normalize (name_tmp); | 1722 | conv_name = GNUNET_GNSRECORD_string_normalize (name_tmp); |
1496 | if (NULL == conv_name) | 1723 | if (NULL == conv_name) |
1497 | { | 1724 | { |
1498 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 1725 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1499 | "Error converting name `%s'\n", | 1726 | "Error normalizing name `%s'\n", |
1500 | name_tmp); | 1727 | name_tmp); |
1501 | GNUNET_SERVICE_client_drop (nc->client); | 1728 | send_store_response (nc, GNUNET_SYSERR, _ ("Error normalizing name."), |
1729 | rid); | ||
1730 | GNUNET_SERVICE_client_continue (nc->client); | ||
1731 | return; | ||
1732 | } | ||
1733 | |||
1734 | /* Check name for validity */ | ||
1735 | if (GNUNET_OK != GNUNET_GNSRECORD_label_check (conv_name, &emsg)) | ||
1736 | { | ||
1737 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1738 | "Label invalid: `%s'\n", | ||
1739 | emsg); | ||
1740 | send_store_response (nc, GNUNET_SYSERR, emsg, rid); | ||
1741 | GNUNET_free (emsg); | ||
1742 | GNUNET_free (conv_name); | ||
1743 | GNUNET_SERVICE_client_continue (nc->client); | ||
1744 | return; | ||
1745 | } | ||
1746 | |||
1747 | if (GNUNET_OK != | ||
1748 | GNUNET_GNSRECORD_records_deserialize (rd_ser_len, rd_ser, rd_count, rd)) | ||
1749 | { | ||
1750 | send_store_response (nc, GNUNET_SYSERR, | ||
1751 | _ ("Error deserializing records."), rid); | ||
1752 | GNUNET_free (conv_name); | ||
1753 | GNUNET_SERVICE_client_continue (nc->client); | ||
1502 | return; | 1754 | return; |
1503 | } | 1755 | } |
1756 | if (GNUNET_YES == ntohl (rp_msg->locking)) | ||
1757 | { | ||
1758 | if (GNUNET_NO == NST_label_lock (conv_name, &rp_msg->private_key, nc)) | ||
1759 | { | ||
1760 | send_store_response (nc, GNUNET_SYSERR, _ ("Record set locked."), rid); | ||
1761 | GNUNET_SERVICE_client_continue (nc->client); | ||
1762 | GNUNET_free (conv_name); | ||
1763 | return; | ||
1764 | } | ||
1765 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1766 | "Client has lock on `%s', continuing.\n", conv_name); | ||
1767 | if (GNUNET_YES == ntohl (rp_msg->locking)) | ||
1768 | NST_label_lock_release (conv_name, &rp_msg->private_key, nc); | ||
1769 | } | ||
1770 | |||
1504 | GNUNET_STATISTICS_update (statistics, | 1771 | GNUNET_STATISTICS_update (statistics, |
1505 | "Well-formed store requests received", | 1772 | "Well-formed store requests received", |
1506 | 1, | 1773 | 1, |
@@ -1509,12 +1776,12 @@ handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg) | |||
1509 | "Creating %u records for name `%s'\n", | 1776 | "Creating %u records for name `%s'\n", |
1510 | (unsigned int) rd_count, | 1777 | (unsigned int) rd_count, |
1511 | conv_name); | 1778 | conv_name); |
1512 | if ((0 == rd_count) && | 1779 | if ((GNUNET_NO == GSN_database->lookup_records (GSN_database->cls, |
1513 | (GNUNET_NO == GSN_database->lookup_records (GSN_database->cls, | ||
1514 | &rp_msg->private_key, | 1780 | &rp_msg->private_key, |
1515 | conv_name, | 1781 | conv_name, |
1516 | NULL, | 1782 | &get_block_exp_existing, |
1517 | 0))) | 1783 | &existing_block_exp)) && |
1784 | (rd_count == 0)) | ||
1518 | { | 1785 | { |
1519 | /* This name does not exist, so cannot be removed */ | 1786 | /* This name does not exist, so cannot be removed */ |
1520 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1787 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
@@ -1525,9 +1792,18 @@ handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg) | |||
1525 | else | 1792 | else |
1526 | { | 1793 | { |
1527 | /* remove "NICK" records, unless this is for the | 1794 | /* remove "NICK" records, unless this is for the |
1528 | #GNUNET_GNS_EMPTY_LABEL_AT label */ | 1795 | #GNUNET_GNS_EMPTY_LABEL_AT label |
1796 | We may need one additional record later for tombstone. | ||
1797 | FIXME: Since we must normalize the record set (check for | ||
1798 | consistency etc) we have to iterate the set twice. | ||
1799 | May be inefficient. | ||
1800 | We cannot really move the nick caching into GNSRECORD. | ||
1801 | */ | ||
1529 | struct GNUNET_GNSRECORD_Data rd_clean[GNUNET_NZL (rd_count)]; | 1802 | struct GNUNET_GNSRECORD_Data rd_clean[GNUNET_NZL (rd_count)]; |
1803 | struct GNUNET_GNSRECORD_Data rd_nf[GNUNET_NZL (rd_count) + 1]; | ||
1530 | unsigned int rd_clean_off; | 1804 | unsigned int rd_clean_off; |
1805 | unsigned int rd_nf_count; | ||
1806 | char *emsg; | ||
1531 | int have_nick; | 1807 | int have_nick; |
1532 | 1808 | ||
1533 | rd_clean_off = 0; | 1809 | rd_clean_off = 0; |
@@ -1535,6 +1811,7 @@ handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg) | |||
1535 | for (unsigned int i = 0; i < rd_count; i++) | 1811 | for (unsigned int i = 0; i < rd_count; i++) |
1536 | { | 1812 | { |
1537 | rd_clean[rd_clean_off] = rd[i]; | 1813 | rd_clean[rd_clean_off] = rd[i]; |
1814 | |||
1538 | if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) || | 1815 | if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) || |
1539 | (GNUNET_GNSRECORD_TYPE_NICK != rd[i].record_type)) | 1816 | (GNUNET_GNSRECORD_TYPE_NICK != rd[i].record_type)) |
1540 | rd_clean_off++; | 1817 | rd_clean_off++; |
@@ -1546,6 +1823,38 @@ handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg) | |||
1546 | have_nick = GNUNET_YES; | 1823 | have_nick = GNUNET_YES; |
1547 | } | 1824 | } |
1548 | } | 1825 | } |
1826 | if (GNUNET_OK != GNUNET_GNSRECORD_normalize_record_set (conv_name, | ||
1827 | rd_clean, | ||
1828 | rd_clean_off, | ||
1829 | rd_nf, | ||
1830 | &rd_nf_count, | ||
1831 | &new_block_exp, | ||
1832 | GNUNET_YES, | ||
1833 | &emsg)) | ||
1834 | { | ||
1835 | send_store_response (nc, GNUNET_SYSERR, emsg, rid); | ||
1836 | GNUNET_free (emsg); | ||
1837 | GNUNET_SERVICE_client_continue (nc->client); | ||
1838 | GNUNET_free (conv_name); | ||
1839 | return; | ||
1840 | } | ||
1841 | /* | ||
1842 | * If existing_block_exp is 0, then there was not record set | ||
1843 | * and no tombstone. | ||
1844 | * Otherwise, if the existing block expiration is after the | ||
1845 | * new block expiration would be, we need to add a tombstone | ||
1846 | * or update it. | ||
1847 | */ | ||
1848 | if (GNUNET_TIME_absolute_cmp (new_block_exp, <=, existing_block_exp)) | ||
1849 | { | ||
1850 | rd_nf[rd_nf_count].record_type = GNUNET_GNSRECORD_TYPE_TOMBSTONE; | ||
1851 | rd_nf[rd_nf_count].expiration_time = | ||
1852 | existing_block_exp.abs_value_us; | ||
1853 | rd_nf[rd_nf_count].data = NULL; | ||
1854 | rd_nf[rd_nf_count].data_size = 0; | ||
1855 | rd_nf[rd_nf_count].flags = GNUNET_GNSRECORD_RF_PRIVATE; | ||
1856 | rd_nf_count++; | ||
1857 | } | ||
1549 | if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) && | 1858 | if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) && |
1550 | (GNUNET_NO == have_nick)) | 1859 | (GNUNET_NO == have_nick)) |
1551 | { | 1860 | { |
@@ -1555,19 +1864,18 @@ handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg) | |||
1555 | res = GSN_database->store_records (GSN_database->cls, | 1864 | res = GSN_database->store_records (GSN_database->cls, |
1556 | &rp_msg->private_key, | 1865 | &rp_msg->private_key, |
1557 | conv_name, | 1866 | conv_name, |
1558 | rd_clean_off, | 1867 | rd_nf_count, |
1559 | rd_clean); | 1868 | rd_nf); |
1560 | } | 1869 | } |
1561 | 1870 | ||
1562 | if (GNUNET_OK != res) | 1871 | if (GNUNET_OK != res) |
1563 | { | 1872 | { |
1564 | /* store not successful, not need to tell monitors */ | 1873 | /* store not successful, no need to tell monitors */ |
1565 | send_store_response (nc, res, rid); | 1874 | send_store_response (nc, res, _ ("Store failed"), rid); |
1566 | GNUNET_SERVICE_client_continue (nc->client); | 1875 | GNUNET_SERVICE_client_continue (nc->client); |
1567 | GNUNET_free (conv_name); | 1876 | GNUNET_free (conv_name); |
1568 | return; | 1877 | return; |
1569 | } | 1878 | } |
1570 | |||
1571 | sa = GNUNET_malloc (sizeof(struct StoreActivity) | 1879 | sa = GNUNET_malloc (sizeof(struct StoreActivity) |
1572 | + ntohs (rp_msg->gns_header.header.size)); | 1880 | + ntohs (rp_msg->gns_header.header.size)); |
1573 | GNUNET_CONTAINER_DLL_insert (sa_head, sa_tail, sa); | 1881 | GNUNET_CONTAINER_DLL_insert (sa_head, sa_tail, sa); |