aboutsummaryrefslogtreecommitdiff
path: root/src/namestore/gnunet-namestore.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/namestore/gnunet-namestore.c')
-rw-r--r--src/namestore/gnunet-namestore.c375
1 files changed, 324 insertions, 51 deletions
diff --git a/src/namestore/gnunet-namestore.c b/src/namestore/gnunet-namestore.c
index c5f48848e..8386a696d 100644
--- a/src/namestore/gnunet-namestore.c
+++ b/src/namestore/gnunet-namestore.c
@@ -33,6 +33,24 @@
33 33
34 34
35/** 35/**
36 * Entry in record set for bulk processing.
37 */
38struct RecordSetEntry
39{
40 /**
41 * Kept in a linked list.
42 */
43 struct RecordSetEntry *next;
44
45 /**
46 * The record to add/remove.
47 */
48 struct GNUNET_GNSRECORD_Data record;
49
50};
51
52
53/**
36 * Handle to the namestore. 54 * Handle to the namestore.
37 */ 55 */
38static struct GNUNET_NAMESTORE_Handle *ns; 56static struct GNUNET_NAMESTORE_Handle *ns;
@@ -118,6 +136,11 @@ static int is_shadow;
118static struct GNUNET_NAMESTORE_QueueEntry *del_qe; 136static struct GNUNET_NAMESTORE_QueueEntry *del_qe;
119 137
120/** 138/**
139 * Queue entry for the 'set/replace' operation.
140 */
141static struct GNUNET_NAMESTORE_QueueEntry *set_qe;
142
143/**
121 * Name of the records to add/list/remove. 144 * Name of the records to add/list/remove.
122 */ 145 */
123static char *name; 146static char *name;
@@ -173,14 +196,9 @@ static void *data;
173static size_t data_size; 196static size_t data_size;
174 197
175/** 198/**
176 * Expirationstring converted to relative time. 199 * Expiration string converted to numeric value.
177 */
178static struct GNUNET_TIME_Relative etime_rel;
179
180/**
181 * Expirationstring converted to absolute time.
182 */ 200 */
183static struct GNUNET_TIME_Absolute etime_abs; 201static uint64_t etime;
184 202
185/** 203/**
186 * Is expiration time relative or absolute time? 204 * Is expiration time relative or absolute time?
@@ -197,6 +215,11 @@ static struct GNUNET_NAMESTORE_ZoneMonitor *zm;
197 */ 215 */
198static int monitor; 216static int monitor;
199 217
218/**
219 * Entry in record set for processing records in bulk.
220 */
221static struct RecordSetEntry *recordset;
222
200 223
201/** 224/**
202 * Task run on shutdown. Cleans up everything. 225 * Task run on shutdown. Cleans up everything.
@@ -232,6 +255,11 @@ do_shutdown (void *cls)
232 GNUNET_NAMESTORE_cancel (add_qe); 255 GNUNET_NAMESTORE_cancel (add_qe);
233 add_qe = NULL; 256 add_qe = NULL;
234 } 257 }
258 if (NULL != set_qe)
259 {
260 GNUNET_NAMESTORE_cancel (set_qe);
261 set_qe = NULL;
262 }
235 if (NULL != add_qe_uri) 263 if (NULL != add_qe_uri)
236 { 264 {
237 GNUNET_NAMESTORE_cancel (add_qe_uri); 265 GNUNET_NAMESTORE_cancel (add_qe_uri);
@@ -516,6 +544,8 @@ display_record_lookup (void *cls,
516 unsigned int rd_len, 544 unsigned int rd_len,
517 const struct GNUNET_GNSRECORD_Data *rd) 545 const struct GNUNET_GNSRECORD_Data *rd)
518{ 546{
547 (void) cls;
548 (void) zone_key;
519 get_qe = NULL; 549 get_qe = NULL;
520 display_record (rname, 550 display_record (rname,
521 rd_len, 551 rd_len,
@@ -694,14 +724,10 @@ get_existing_record (void *cls,
694 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD; 724 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
695 if (1 != is_public) 725 if (1 != is_public)
696 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE; 726 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
727 rde->expiration_time = etime;
697 if (GNUNET_YES == etime_is_rel) 728 if (GNUNET_YES == etime_is_rel)
698 {
699 rde->expiration_time = etime_rel.rel_value_us;
700 rde->flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; 729 rde->flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
701 } 730 else if (GNUNET_NO != etime_is_rel)
702 else if (GNUNET_NO == etime_is_rel)
703 rde->expiration_time = etime_abs.abs_value_us;
704 else
705 rde->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us; 731 rde->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
706 GNUNET_assert (NULL != name); 732 GNUNET_assert (NULL != name);
707 add_qe = GNUNET_NAMESTORE_records_store (ns, 733 add_qe = GNUNET_NAMESTORE_records_store (ns,
@@ -864,6 +890,85 @@ del_monitor (void *cls,
864 890
865 891
866/** 892/**
893 * Parse expiration time.
894 *
895 * @param expirationstring text to parse
896 * @param etime_is_rel[out] set to #GNUNET_YES if time is relative
897 * @param etime[out] set to expiration time (abs or rel)
898 * @return #GNUNET_OK on success
899 */
900static int
901parse_expiration (const char *expirationstring,
902 int *etime_is_rel,
903 uint64_t *etime)
904{
905 struct GNUNET_TIME_Relative etime_rel;
906 struct GNUNET_TIME_Absolute etime_abs;
907
908 if (0 == strcmp (expirationstring,
909 "never"))
910 {
911 *etime = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
912 *etime_is_rel = GNUNET_NO;
913 return GNUNET_OK;
914 }
915 if (GNUNET_OK ==
916 GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
917 &etime_rel))
918 {
919 *etime_is_rel = GNUNET_YES;
920 *etime = etime_rel.rel_value_us;
921 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
922 "Storing record with relative expiration time of %s\n",
923 GNUNET_STRINGS_relative_time_to_string (etime_rel,
924 GNUNET_NO));
925 return GNUNET_OK;
926 }
927 if (GNUNET_OK ==
928 GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
929 &etime_abs))
930 {
931 *etime_is_rel = GNUNET_NO;
932 *etime = etime_abs.abs_value_us;
933 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
934 "Storing record with absolute expiration time of %s\n",
935 GNUNET_STRINGS_absolute_time_to_string (etime_abs));
936 return GNUNET_OK;
937 }
938 return GNUNET_SYSERR;
939}
940
941
942/**
943 * Function called when namestore is done with the replace
944 * operation.
945 *
946 * @param cls NULL
947 * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
948 * #GNUNET_NO if content was already there or not found
949 * #GNUNET_YES (or other positive value) on success
950 * @param emsg NULL on success, otherwise an error message
951 */
952static void
953replace_cont (void *cls,
954 int success,
955 const char *emsg)
956{
957 (void) cls;
958
959 set_qe = NULL;
960 if (GNUNET_OK != success)
961 {
962 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
963 _("Failed to replace records: %s\n"),
964 emsg);
965 ret = 1; /* fail from 'main' */
966 }
967 GNUNET_SCHEDULER_shutdown ();
968}
969
970
971/**
867 * Callback invoked from identity service with ego information. 972 * Callback invoked from identity service with ego information.
868 * An @a ego of NULL means the ego was not found. 973 * An @a ego of NULL means the ego was not found.
869 * 974 *
@@ -895,7 +1000,7 @@ identity_cb (void *cls,
895 GNUNET_free_non_null (ego_name); 1000 GNUNET_free_non_null (ego_name);
896 ego_name = NULL; 1001 ego_name = NULL;
897 1002
898 if (! (add|del|list|(NULL != nickstring)|(NULL != uri)|(NULL != reverse_pkey)) ) 1003 if (! (add|del|list|(NULL != nickstring)|(NULL != uri)|(NULL != reverse_pkey))|(NULL != recordset) )
899 { 1004 {
900 /* nothing more to be done */ 1005 /* nothing more to be done */
901 fprintf (stderr, 1006 fprintf (stderr,
@@ -904,8 +1009,7 @@ identity_cb (void *cls,
904 return; 1009 return;
905 } 1010 }
906 GNUNET_CRYPTO_ecdsa_key_get_public (&zone_pkey, 1011 GNUNET_CRYPTO_ecdsa_key_get_public (&zone_pkey,
907 &pub); 1012 &pub);
908
909 ns = GNUNET_NAMESTORE_connect (cfg); 1013 ns = GNUNET_NAMESTORE_connect (cfg);
910 if (NULL == ns) 1014 if (NULL == ns)
911 { 1015 {
@@ -913,6 +1017,44 @@ identity_cb (void *cls,
913 _("Failed to connect to namestore\n")); 1017 _("Failed to connect to namestore\n"));
914 return; 1018 return;
915 } 1019 }
1020
1021 if (NULL != recordset)
1022 {
1023 /* replace entire record set */
1024 unsigned int rd_count;
1025 struct GNUNET_GNSRECORD_Data *rd;
1026
1027 if (NULL == name)
1028 {
1029 fprintf (stderr,
1030 _("Missing option `%s' for operation `%s'\n"),
1031 "-n", _("replace"));
1032 GNUNET_SCHEDULER_shutdown ();
1033 ret = 1;
1034 return;
1035 }
1036 rd_count = 0;
1037 for (struct RecordSetEntry *e = recordset; NULL != e; e = e->next)
1038 rd_count++;
1039 rd = GNUNET_new_array (rd_count,
1040 struct GNUNET_GNSRECORD_Data);
1041 rd_count = 0;
1042 for (struct RecordSetEntry *e = recordset; NULL != e; e = e->next)
1043 {
1044 rd[rd_count] = e->record;
1045 rd_count++;
1046 }
1047 set_qe = GNUNET_NAMESTORE_records_store (ns,
1048 &zone_pkey,
1049 name,
1050 rd_count,
1051 rd,
1052 &replace_cont,
1053 NULL);
1054 GNUNET_free (rd);
1055 return;
1056 }
1057
916 if (add) 1058 if (add)
917 { 1059 {
918 if (NULL == name) 1060 if (NULL == name)
@@ -976,32 +1118,10 @@ identity_cb (void *cls,
976 ret = 1; 1118 ret = 1;
977 return; 1119 return;
978 } 1120 }
979 if (0 == strcmp (expirationstring, 1121 if (GNUNET_OK !=
980 "never")) 1122 parse_expiration (expirationstring,
981 { 1123 &etime_is_rel,
982 etime_abs = GNUNET_TIME_UNIT_FOREVER_ABS; 1124 &etime))
983 etime_is_rel = GNUNET_NO;
984 }
985 else if (GNUNET_OK ==
986 GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
987 &etime_rel))
988 {
989 etime_is_rel = GNUNET_YES;
990 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
991 "Storing record with relative expiration time of %s\n",
992 GNUNET_STRINGS_relative_time_to_string (etime_rel,
993 GNUNET_NO));
994 }
995 else if (GNUNET_OK ==
996 GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
997 &etime_abs))
998 {
999 etime_is_rel = GNUNET_NO;
1000 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1001 "Storing record with absolute expiration time of %s\n",
1002 GNUNET_STRINGS_absolute_time_to_string (etime_abs));
1003 }
1004 else
1005 { 1125 {
1006 fprintf (stderr, 1126 fprintf (stderr,
1007 _("Invalid time format `%s'\n"), 1127 _("Invalid time format `%s'\n"),
@@ -1106,16 +1226,9 @@ identity_cb (void *cls,
1106 rd.data = &pkey; 1226 rd.data = &pkey;
1107 rd.data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey); 1227 rd.data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
1108 rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY; 1228 rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
1109 if (GNUNET_YES == etime_is_rel) 1229 rd.expiration_time = etime;
1110 { 1230 if (GNUNET_YES == etime_is_rel)
1111 rd.expiration_time = etime_rel.rel_value_us;
1112 rd.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; 1231 rd.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1113 }
1114 else if (GNUNET_NO == etime_is_rel)
1115 rd.expiration_time = etime_abs.abs_value_us;
1116 else
1117 rd.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
1118
1119 if (1 == is_shadow) 1232 if (1 == is_shadow)
1120 rd.flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD; 1233 rd.flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
1121 add_qe_uri = GNUNET_NAMESTORE_records_store (ns, 1234 add_qe_uri = GNUNET_NAMESTORE_records_store (ns,
@@ -1247,6 +1360,161 @@ run (void *cls,
1247 1360
1248 1361
1249/** 1362/**
1363 * Command-line option parser function that allows the user to specify
1364 * a complete record as one argument for adding/removing. A pointer
1365 * to the head of the list of record sets must be passed as the "scls"
1366 * argument.
1367 *
1368 * @param ctx command line processor context
1369 * @param scls must be of type "struct GNUNET_FS_Uri **"
1370 * @param option name of the option (typically 'R')
1371 * @param value command line argument given; format is
1372 * "TTL TYPE FLAGS VALUE" where TTL is an expiration time (rel or abs),
1373 * TYPE is a DNS/GNS record type, FLAGS is either "n" for no flags or
1374 * a combination of 's' (shadow) and 'p' (public) and VALUE is the
1375 * value (in human-readable format)
1376 * @return #GNUNET_OK on success
1377 */
1378static int
1379multirecord_process (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
1380 void *scls,
1381 const char *option,
1382 const char *value)
1383{
1384 struct RecordSetEntry **head = scls;
1385 struct RecordSetEntry *r;
1386 struct GNUNET_GNSRECORD_Data record;
1387 char *cp;
1388 char *tok;
1389 int etime_is_rel;
1390 void *raw_data;
1391
1392 (void) ctx;
1393 (void) option;
1394 cp = GNUNET_strdup (value);
1395 tok = strtok (cp, " ");
1396 if (NULL == tok)
1397 {
1398 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1399 _("Empty record line argument is not allowed.\n"));
1400 GNUNET_free (cp);
1401 return GNUNET_SYSERR;
1402 }
1403 if (GNUNET_OK !=
1404 parse_expiration (tok,
1405 &etime_is_rel,
1406 &record.expiration_time))
1407 {
1408 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1409 _("Invalid expiration time `%s'\n"),
1410 tok);
1411 GNUNET_free (cp);
1412 return GNUNET_SYSERR;
1413 }
1414 tok = strtok (NULL, " ");
1415 if (NULL == tok)
1416 {
1417 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1418 _("Missing entries in record line `%s'.\n"),
1419 value);
1420 GNUNET_free (cp);
1421 return GNUNET_SYSERR;
1422 }
1423 record.record_type = GNUNET_GNSRECORD_typename_to_number (tok);
1424 if (UINT32_MAX == record.record_type)
1425 {
1426 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1427 _("Unknown record type `%s'\n"),
1428 tok);
1429 GNUNET_free (cp);
1430 return GNUNET_SYSERR;
1431 }
1432 tok = strtok (NULL, " ");
1433 if (NULL == tok)
1434 {
1435 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1436 _("Missing entries in record line `%s'.\n"),
1437 value);
1438 GNUNET_free (cp);
1439 return GNUNET_SYSERR;
1440 }
1441 record.flags = GNUNET_GNSRECORD_RF_NONE;
1442 if (etime_is_rel)
1443 record.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1444 if (NULL == strchr (tok, (unsigned char) 'p')) /* p = public */
1445 record.flags |= GNUNET_GNSRECORD_RF_PRIVATE;
1446 if (NULL != strchr (tok, (unsigned char) 's'))
1447 record.flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
1448 /* find beginning of record value */
1449 tok = strchr (&value[tok - cp], (unsigned char) ' ');
1450 if (NULL == tok)
1451 {
1452 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1453 _("Missing entries in record line `%s'.\n"),
1454 value);
1455 GNUNET_free (cp);
1456 return GNUNET_SYSERR;
1457 }
1458 GNUNET_free (cp);
1459 tok++; /* skip space */
1460 if (GNUNET_OK !=
1461 GNUNET_GNSRECORD_string_to_value (record.record_type,
1462 tok,
1463 &raw_data,
1464 &record.data_size))
1465 {
1466 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1467 _("Invalid record data for type %s: `%s'.\n"),
1468 GNUNET_GNSRECORD_number_to_typename (record.record_type),
1469 tok);
1470 return GNUNET_SYSERR;
1471 }
1472
1473 r = GNUNET_malloc (sizeof (struct RecordSetEntry) + record.data_size);
1474 r->next = *head;
1475 record.data = &r[1];
1476 memcpy (&r[1],
1477 raw_data,
1478 record.data_size);
1479 GNUNET_free (raw_data);
1480 r->record = record;
1481 *head = r;
1482 return GNUNET_OK;
1483}
1484
1485
1486/**
1487 * Allow user to specify keywords.
1488 *
1489 * @param shortName short name of the option
1490 * @param name long name of the option
1491 * @param argumentHelp help text for the option argument
1492 * @param description long help text for the option
1493 * @param[out] topKeywords set to the desired value
1494 */
1495struct GNUNET_GETOPT_CommandLineOption
1496multirecord_option (char shortName,
1497 const char *name,
1498 const char *argumentHelp,
1499 const char *description,
1500 struct RecordSetEntry **rs)
1501{
1502 struct GNUNET_GETOPT_CommandLineOption clo = {
1503 .shortName = shortName,
1504 .name = name,
1505 .argumentHelp = argumentHelp,
1506 .description = description,
1507 .require_argument = 1,
1508 .processor = &multirecord_process,
1509 .scls = (void *) rs
1510 };
1511
1512 return clo;
1513}
1514
1515
1516
1517/**
1250 * The main function for gnunet-namestore. 1518 * The main function for gnunet-namestore.
1251 * 1519 *
1252 * @param argc number of arguments from the command line 1520 * @param argc number of arguments from the command line
@@ -1294,6 +1562,11 @@ main (int argc,
1294 "PKEY", 1562 "PKEY",
1295 gettext_noop ("determine our name for the given PKEY"), 1563 gettext_noop ("determine our name for the given PKEY"),
1296 &reverse_pkey), 1564 &reverse_pkey),
1565 multirecord_option ('R',
1566 "replace",
1567 "RECORDLINE",
1568 gettext_noop ("set record set to values given by (possibly multiple) RECORDLINES; can be specified multiple times"),
1569 &recordset),
1297 GNUNET_GETOPT_option_string ('t', 1570 GNUNET_GETOPT_option_string ('t',
1298 "type", 1571 "type",
1299 "TYPE", 1572 "TYPE",