aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/fs/fs.c301
-rw-r--r--src/fs/fs.h209
-rw-r--r--src/fs/fs_search.c150
3 files changed, 507 insertions, 153 deletions
diff --git a/src/fs/fs.c b/src/fs/fs.c
index 94777fb05..5b8dc3e90 100644
--- a/src/fs/fs.c
+++ b/src/fs/fs.c
@@ -127,9 +127,6 @@ process_job_queue (void *cls,
127 while (NULL != (qe = next)) 127 while (NULL != (qe = next))
128 { 128 {
129 next = qe->next; 129 next = qe->next;
130 /* FIXME: might be faster/simpler to do this calculation only once
131 when we start a job (OTOH, this would allow us to dynamically
132 and easily adjust qe->blocks over time, given the right API...) */
133 run_time = GNUNET_TIME_relative_multiply (h->avg_block_latency, 130 run_time = GNUNET_TIME_relative_multiply (h->avg_block_latency,
134 qe->blocks * qe->start_times); 131 qe->blocks * qe->start_times);
135 end_time = GNUNET_TIME_absolute_add (qe->start_time, 132 end_time = GNUNET_TIME_absolute_add (qe->start_time,
@@ -1249,6 +1246,21 @@ GNUNET_FS_unindex_sync_ (struct GNUNET_FS_UnindexContext *uc)
1249 1246
1250 1247
1251/** 1248/**
1249 * Synchronize this search result with its mirror
1250 * on disk. Note that all internal FS-operations that change
1251 * publishing structs should already call "sync" internally,
1252 * so this function is likely not useful for clients.
1253 *
1254 * @param sc the struct to sync
1255 */
1256void
1257GNUNET_FS_search_result_sync_ (struct SearchResult *sr)
1258{
1259 /* FIXME */
1260}
1261
1262
1263/**
1252 * Synchronize this search struct with its mirror 1264 * Synchronize this search struct with its mirror
1253 * on disk. Note that all internal FS-operations that change 1265 * on disk. Note that all internal FS-operations that change
1254 * publishing structs should already call "sync" internally, 1266 * publishing structs should already call "sync" internally,
@@ -1290,7 +1302,7 @@ GNUNET_FS_search_sync_ (struct GNUNET_FS_SearchContext *sc)
1290 return; 1302 return;
1291 } 1303 }
1292#endif 1304#endif
1293 /* FIXME: do search-specific deserialization here! */ 1305 /* FIXME: do search-specific serialization here! */
1294 if (GNUNET_OK != 1306 if (GNUNET_OK !=
1295 GNUNET_BIO_write_close (wh)) 1307 GNUNET_BIO_write_close (wh))
1296 { 1308 {
@@ -1462,6 +1474,250 @@ deserialize_unindex (struct GNUNET_FS_Handle *h)
1462} 1474}
1463 1475
1464 1476
1477/**
1478 * Function called with a filename of serialized search result
1479 * to deserialize.
1480 *
1481 * @param cls the 'struct GNUNET_FS_SearchContext*'
1482 * @param filename complete filename (absolute path)
1483 * @return GNUNET_OK (continue to iterate)
1484 */
1485static int
1486deserialize_search_result (void *cls,
1487 const char *filename)
1488{
1489 struct GNUNET_FS_SearchContext *sc = cls;
1490 char pbuf[32];
1491 char *ser;
1492 char *uris;
1493 char *emsg;
1494 struct GNUNET_BIO_ReadHandle *rh;
1495 struct SearchResult *sr;
1496 GNUNET_HashCode key;
1497
1498 ser = get_serialization_short_name (filename);
1499 rh = GNUNET_BIO_read_open (filename);
1500 if (rh == NULL)
1501 {
1502 if (ser != NULL)
1503 {
1504 GNUNET_snprintf (pbuf,
1505 sizeof (pbuf),
1506 "%s%s%s",
1507 "search-results",
1508 DIR_SEPARATOR_STR,
1509 sc->serialization);
1510 GNUNET_FS_remove_sync_file_ (sc->h, pbuf, ser);
1511 GNUNET_free (ser);
1512 }
1513 return GNUNET_OK;
1514 }
1515 emsg = NULL;
1516 uris = NULL;
1517 sr = GNUNET_malloc (sizeof (struct SearchResult));
1518 sr->serialization = ser;
1519 if ( (GNUNET_OK !=
1520 GNUNET_BIO_read_string (rh, "result-uri", &uris, 10*1024)) ||
1521 (NULL == (sr->uri = GNUNET_FS_uri_parse (uris, &emsg))) ||
1522 ( (GNUNET_YES != GNUNET_FS_uri_test_chk (sr->uri)) &&
1523 (GNUNET_YES != GNUNET_FS_uri_test_loc (sr->uri)) ) ||
1524 (GNUNET_OK !=
1525 GNUNET_BIO_read_meta_data (rh, "result-meta", &sr->meta)) ||
1526 (GNUNET_OK !=
1527 GNUNET_BIO_read (rh, "result-key", &key, sizeof (key))) ||
1528 (GNUNET_OK !=
1529 GNUNET_BIO_read_int32 (rh, &sr->mandatory_missing)) ||
1530 (GNUNET_OK !=
1531 GNUNET_BIO_read_int32 (rh, &sr->optional_support)) ||
1532 (GNUNET_OK !=
1533 GNUNET_BIO_read_int32 (rh, &sr->availability_success)) ||
1534 (GNUNET_OK !=
1535 GNUNET_BIO_read_int32 (rh, &sr->availability_trials)) )
1536 goto cleanup;
1537 GNUNET_free (uris);
1538 GNUNET_CONTAINER_multihashmap_put (sc->master_result_map,
1539 &key,
1540 sr,
1541 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1542 return GNUNET_OK;
1543 cleanup:
1544 GNUNET_free_non_null (emsg);
1545 GNUNET_free_non_null (uris);
1546 if (sr->uri != NULL)
1547 GNUNET_FS_uri_destroy (sr->uri);
1548 if (sr->meta != NULL)
1549 GNUNET_CONTAINER_meta_data_destroy (sr->meta);
1550 GNUNET_free (sr->serialization);
1551 GNUNET_free (sr);
1552 return GNUNET_OK;
1553}
1554
1555
1556/**
1557 * Iterator over search results signaling resume to the client for
1558 * each result.
1559 *
1560 * @param cls closure, the 'struct GNUNET_FS_SearchContext'
1561 * @param key current key code
1562 * @param value value in the hash map, the 'struct SearchResult'
1563 * @return GNUNET_YES (we should continue to iterate)
1564 */
1565static int
1566signal_result_resume (void *cls,
1567 const GNUNET_HashCode * key,
1568 void *value)
1569{
1570 struct GNUNET_FS_SearchContext *sc = cls;
1571 struct GNUNET_FS_ProgressInfo pi;
1572 struct SearchResult *sr = value;
1573
1574 if (0 == sr->mandatory_missing)
1575 {
1576 pi.status = GNUNET_FS_STATUS_SEARCH_RESUME_RESULT;
1577 pi.value.search.specifics.resume_result.meta = sr->meta;
1578 pi.value.search.specifics.resume_result.uri = sr->uri;
1579 pi.value.search.specifics.resume_result.availability_rank = 2*sr->availability_success - sr->availability_trials;
1580 pi.value.search.specifics.resume_result.availability_certainty = sr->availability_trials;
1581 pi.value.search.specifics.resume_result.applicability_rank = sr->optional_support;
1582 sr->client_info = GNUNET_FS_search_make_status_ (&pi,
1583 sc);
1584 }
1585 GNUNET_FS_search_start_probe_ (sr);
1586 return GNUNET_YES;
1587}
1588
1589
1590/**
1591 * Iterator over search results freeing each.
1592 *
1593 * @param cls closure, the 'struct GNUNET_FS_SearchContext'
1594 * @param key current key code
1595 * @param value value in the hash map, the 'struct SearchResult'
1596 * @return GNUNET_YES (we should continue to iterate)
1597 */
1598static int
1599free_result (void *cls,
1600 const GNUNET_HashCode * key,
1601 void *value)
1602{
1603 struct SearchResult *sr = value;
1604
1605 GNUNET_CONTAINER_meta_data_destroy (sr->meta);
1606 GNUNET_FS_uri_destroy (sr->uri);
1607 GNUNET_free (sr);
1608 return GNUNET_YES;
1609}
1610
1611
1612/**
1613 * Deserialize a search.
1614 *
1615 * @param h overall context
1616 * @param rh file to deserialize from
1617 * @param parent parent search
1618 * @param serialization name under which the search was serialized
1619 */
1620static struct GNUNET_FS_SearchContext *
1621deserialize_search (struct GNUNET_FS_Handle *h,
1622 struct GNUNET_BIO_ReadHandle *rh,
1623 struct GNUNET_FS_SearchContext *parent,
1624 const char *serialization)
1625{
1626 struct GNUNET_FS_SearchContext *sc;
1627 char pbuf[32];
1628 struct GNUNET_FS_ProgressInfo pi;
1629 char *emsg;
1630 char *uris;
1631 char *child_ser;
1632 char *dn;
1633 uint32_t options;
1634 char in_pause;
1635
1636 uris = NULL;
1637 child_ser = NULL;
1638 emsg = NULL;
1639 sc = GNUNET_malloc (sizeof (struct GNUNET_FS_SearchContext));
1640 sc->parent = parent;
1641 sc->h = h;
1642 sc->serialization = GNUNET_strdup (serialization);
1643 if ( (GNUNET_OK !=
1644 GNUNET_BIO_read_string (rh, "search-uri", &uris, 10*1024)) ||
1645 (NULL == (sc->uri = GNUNET_FS_uri_parse (uris, &emsg))) ||
1646 ( (GNUNET_YES != GNUNET_FS_uri_test_ksk (sc->uri)) &&
1647 (GNUNET_YES != GNUNET_FS_uri_test_sks (sc->uri)) ) ||
1648 (GNUNET_OK !=
1649 GNUNET_BIO_read_int64 (rh, &sc->start_time.value)) ||
1650 (GNUNET_OK !=
1651 GNUNET_BIO_read_string (rh, "child-serialization", &child_ser, 32)) ||
1652 (GNUNET_OK !=
1653 GNUNET_BIO_read_string (rh, "search-emsg", &sc->emsg, 10*1024)) ||
1654 (GNUNET_OK !=
1655 GNUNET_BIO_read_int32 (rh, &options)) ||
1656 (GNUNET_OK !=
1657 GNUNET_BIO_read (rh, "search-pause", &in_pause, sizeof (in_pause))) ||
1658 (GNUNET_OK !=
1659 GNUNET_BIO_read_int32 (rh, &sc->anonymity)) )
1660 goto cleanup;
1661 /* FIXME: adjust start_time.value */
1662 sc->options = (enum GNUNET_FS_SearchOptions) options;
1663 sc->master_result_map = GNUNET_CONTAINER_multihashmap_create (16);
1664 GNUNET_snprintf (pbuf,
1665 sizeof (pbuf),
1666 "%s%s%s",
1667 "search-results",
1668 DIR_SEPARATOR_STR,
1669 sc->serialization);
1670 dn = get_serialization_file_name (h, pbuf, "");
1671 if (dn != NULL)
1672 {
1673 GNUNET_DISK_directory_scan (dn, &deserialize_search_result, sc);
1674 GNUNET_free (dn);
1675 }
1676 if ('\0' == in_pause)
1677 {
1678 if (GNUNET_OK !=
1679 GNUNET_FS_search_start_searching_ (sc))
1680 goto cleanup;
1681 }
1682 if (child_ser != NULL)
1683 {
1684 /* FIXME: deserialize child-search! */
1685 }
1686 if (parent != NULL)
1687 GNUNET_CONTAINER_DLL_insert (parent->child_head,
1688 parent->child_tail,
1689 sc);
1690 pi.status = GNUNET_FS_STATUS_SEARCH_RESUME;
1691 pi.value.search.specifics.resume.message = sc->emsg;
1692 pi.value.search.specifics.resume.is_paused = ('\0' == in_pause) ? GNUNET_NO : GNUNET_YES;
1693 sc->client_info = GNUNET_FS_search_make_status_ (&pi,
1694 sc);
1695 GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
1696 &signal_result_resume,
1697 sc);
1698 return sc;
1699 cleanup:
1700 GNUNET_free_non_null (child_ser);
1701 GNUNET_free_non_null (sc->emsg);
1702 GNUNET_free_non_null (emsg);
1703 if (sc->serialization != NULL)
1704 GNUNET_FS_remove_sync_file_ (h, "search", sc->serialization);
1705 /* FIXME: remove 'pbuf' directory with search results as well! */
1706 GNUNET_free_non_null (sc->serialization);
1707 if (sc->uri != NULL)
1708 GNUNET_FS_uri_destroy (sc->uri);
1709 if (sc->master_result_map != NULL)
1710 {
1711 GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
1712 &free_result,
1713 sc);
1714 GNUNET_CONTAINER_multihashmap_destroy (sc->master_result_map);
1715 }
1716 GNUNET_free (sc);
1717 GNUNET_free_non_null (uris);
1718 return NULL;
1719}
1720
1465 1721
1466/** 1722/**
1467 * Function called with a filename of serialized search operation 1723 * Function called with a filename of serialized search operation
@@ -1475,11 +1731,34 @@ static int
1475deserialize_search_file (void *cls, 1731deserialize_search_file (void *cls,
1476 const char *filename) 1732 const char *filename)
1477{ 1733{
1478 /* FIXME */ 1734 struct GNUNET_FS_Handle *h = cls;
1479 // Deserialize Search: 1735 char *ser;
1480 // * for each query, read file with search results 1736 char *emsg;
1481 // * for each search result with active download, deserialize download 1737 struct GNUNET_BIO_ReadHandle *rh;
1482 // * for each directory search result, check for active downloads of contents 1738 struct GNUNET_FS_SearchContext *sc;
1739
1740 ser = get_serialization_short_name (filename);
1741 rh = GNUNET_BIO_read_open (filename);
1742 if (rh == NULL)
1743 {
1744 if (ser != NULL)
1745 {
1746 GNUNET_FS_remove_sync_file_ (h, "search", ser);
1747 GNUNET_free (ser);
1748 }
1749 return GNUNET_OK;
1750 }
1751 sc = deserialize_search (h, rh, NULL, ser);
1752 GNUNET_free (ser);
1753 if (GNUNET_OK !=
1754 GNUNET_BIO_read_close (rh, &emsg))
1755 {
1756 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1757 _("Failure while resuming unindexing operation `%s': %s\n"),
1758 filename,
1759 emsg);
1760 GNUNET_free (emsg);
1761 }
1483 return GNUNET_OK; 1762 return GNUNET_OK;
1484} 1763}
1485 1764
@@ -1490,7 +1769,7 @@ deserialize_search_file (void *cls,
1490 * @param h master context 1769 * @param h master context
1491 */ 1770 */
1492static void 1771static void
1493deserialize_search (struct GNUNET_FS_Handle *h) 1772deserialize_search_master (struct GNUNET_FS_Handle *h)
1494{ 1773{
1495 char *dn; 1774 char *dn;
1496 1775
@@ -1570,7 +1849,7 @@ GNUNET_FS_start (struct GNUNET_SCHEDULER_Handle *sched,
1570 /* FIXME: could write one generic deserialization 1849 /* FIXME: could write one generic deserialization
1571 function instead of these four... */ 1850 function instead of these four... */
1572 deserialize_publish (ret); 1851 deserialize_publish (ret);
1573 deserialize_search (ret); 1852 deserialize_search_master (ret);
1574 /* FIXME: deserialize downloads that are NOT part of searches */ 1853 /* FIXME: deserialize downloads that are NOT part of searches */
1575 deserialize_unindex (ret); 1854 deserialize_unindex (ret);
1576 } 1855 }
diff --git a/src/fs/fs.h b/src/fs/fs.h
index 3c111f33e..33ee8dde0 100644
--- a/src/fs/fs.h
+++ b/src/fs/fs.h
@@ -342,8 +342,7 @@ struct GNUNET_FS_FileInformation
342 struct GNUNET_FS_TreeEncoder *te; 342 struct GNUNET_FS_TreeEncoder *te;
343 343
344 /** 344 /**
345 * Error message (non-NULL if this operation 345 * Error message (non-NULL if this operation failed).
346 * failed).
347 */ 346 */
348 char *emsg; 347 char *emsg;
349 348
@@ -543,6 +542,87 @@ struct GNUNET_FS_QueueEntry
543 542
544 543
545/** 544/**
545 * Information we store for each search result.
546 */
547struct SearchResult
548{
549
550 /**
551 * Search context this result belongs to.
552 */
553 struct GNUNET_FS_SearchContext *sc;
554
555 /**
556 * URI to which this search result refers to.
557 */
558 struct GNUNET_FS_Uri *uri;
559
560 /**
561 * Metadata for the search result.
562 */
563 struct GNUNET_CONTAINER_MetaData *meta;
564
565 /**
566 * Client info for this search result.
567 */
568 void *client_info;
569
570 /**
571 * ID of a job that is currently probing this results' availability
572 * (NULL if we are not currently probing).
573 */
574 struct GNUNET_FS_DownloadContext *probe_ctx;
575
576 /**
577 * Name under which this search result is stored on disk.
578 */
579 char *serialization;
580
581 /**
582 * ID of the task that will clean up the probe_ctx should it not
583 * complete on time (and that will need to be cancelled if we clean
584 * up the search result before then).
585 */
586 GNUNET_SCHEDULER_TaskIdentifier probe_cancel_task;
587
588 /**
589 * When did the current probe become active?
590 */
591 struct GNUNET_TIME_Absolute probe_active_time;
592
593 /**
594 * How much longer should we run the current probe before giving up?
595 */
596 struct GNUNET_TIME_Relative remaining_probe_time;
597
598 /**
599 * Number of mandatory keywords for which we have NOT yet found the
600 * search result; when this value hits zero, the search result is
601 * given to the callback.
602 */
603 uint32_t mandatory_missing;
604
605 /**
606 * Number of optional keywords under which this result was also
607 * found.
608 */
609 uint32_t optional_support;
610
611 /**
612 * Number of availability tests that have succeeded for this result.
613 */
614 uint32_t availability_success;
615
616 /**
617 * Number of availability trials that we have performed for this
618 * search result.
619 */
620 uint32_t availability_trials;
621
622};
623
624
625/**
546 * Add a job to the queue. 626 * Add a job to the queue.
547 * 627 *
548 * @param h handle to the overall FS state 628 * @param h handle to the overall FS state
@@ -699,6 +779,19 @@ GNUNET_FS_unindex_make_status_ (struct GNUNET_FS_ProgressInfo *pi,
699 uint64_t offset); 779 uint64_t offset);
700 780
701/** 781/**
782 * Fill in all of the generic fields for a search event and
783 * call the callback.
784 *
785 * @param pi structure to fill in
786 * @param sc overall search context
787 * @return value returned by the callback
788 */
789void *
790GNUNET_FS_search_make_status_ (struct GNUNET_FS_ProgressInfo *pi,
791 struct GNUNET_FS_SearchContext *sc);
792
793
794/**
702 * Connect to the datastore and remove the blocks. 795 * Connect to the datastore and remove the blocks.
703 * 796 *
704 * @param uc context for the unindex operation. 797 * @param uc context for the unindex operation.
@@ -706,6 +799,23 @@ GNUNET_FS_unindex_make_status_ (struct GNUNET_FS_ProgressInfo *pi,
706void 799void
707GNUNET_FS_unindex_do_remove_ (struct GNUNET_FS_UnindexContext *uc); 800GNUNET_FS_unindex_do_remove_ (struct GNUNET_FS_UnindexContext *uc);
708 801
802/**
803 * Build the request and actually initiate the search using the
804 * GNUnet FS service.
805 *
806 * @param sc search context
807 * @return GNUNET_OK on success, GNUNET_SYSERR on error
808 */
809int
810GNUNET_FS_search_start_searching_ (struct GNUNET_FS_SearchContext *sc);
811
812/**
813 * Start download probes for the given search result.
814 *
815 * @param sr the search result
816 */
817void
818GNUNET_FS_search_start_probe_ (struct SearchResult *sr);
709 819
710/** 820/**
711 * Remove serialization/deserialization file from disk. 821 * Remove serialization/deserialization file from disk.
@@ -731,7 +841,6 @@ GNUNET_FS_remove_sync_file_ (struct GNUNET_FS_Handle *h,
731void 841void
732GNUNET_FS_file_information_sync_ (struct GNUNET_FS_FileInformation *f); 842GNUNET_FS_file_information_sync_ (struct GNUNET_FS_FileInformation *f);
733 843
734
735/** 844/**
736 * Synchronize this publishing struct with its mirror 845 * Synchronize this publishing struct with its mirror
737 * on disk. Note that all internal FS-operations that change 846 * on disk. Note that all internal FS-operations that change
@@ -743,7 +852,6 @@ GNUNET_FS_file_information_sync_ (struct GNUNET_FS_FileInformation *f);
743void 852void
744GNUNET_FS_publish_sync_ (struct GNUNET_FS_PublishContext *pc); 853GNUNET_FS_publish_sync_ (struct GNUNET_FS_PublishContext *pc);
745 854
746
747/** 855/**
748 * Synchronize this unindex struct with its mirror 856 * Synchronize this unindex struct with its mirror
749 * on disk. Note that all internal FS-operations that change 857 * on disk. Note that all internal FS-operations that change
@@ -755,8 +863,6 @@ GNUNET_FS_publish_sync_ (struct GNUNET_FS_PublishContext *pc);
755void 863void
756GNUNET_FS_unindex_sync_ (struct GNUNET_FS_UnindexContext *uc); 864GNUNET_FS_unindex_sync_ (struct GNUNET_FS_UnindexContext *uc);
757 865
758
759
760/** 866/**
761 * Synchronize this search struct with its mirror 867 * Synchronize this search struct with its mirror
762 * on disk. Note that all internal FS-operations that change 868 * on disk. Note that all internal FS-operations that change
@@ -768,6 +874,16 @@ GNUNET_FS_unindex_sync_ (struct GNUNET_FS_UnindexContext *uc);
768void 874void
769GNUNET_FS_search_sync_ (struct GNUNET_FS_SearchContext *sc); 875GNUNET_FS_search_sync_ (struct GNUNET_FS_SearchContext *sc);
770 876
877/**
878 * Synchronize this search result with its mirror
879 * on disk. Note that all internal FS-operations that change
880 * publishing structs should already call "sync" internally,
881 * so this function is likely not useful for clients.
882 *
883 * @param sc the struct to sync
884 */
885void
886GNUNET_FS_search_result_sync_ (struct SearchResult *sr);
771 887
772 888
773/** 889/**
@@ -1069,82 +1185,6 @@ struct GNUNET_FS_UnindexContext
1069 1185
1070 1186
1071/** 1187/**
1072 * Information we store for each search result.
1073 */
1074struct SearchResult
1075{
1076
1077 /**
1078 * Search context this result belongs to.
1079 */
1080 struct GNUNET_FS_SearchContext *sc;
1081
1082 /**
1083 * URI to which this search result refers to.
1084 */
1085 struct GNUNET_FS_Uri *uri;
1086
1087 /**
1088 * Metadata for the search result.
1089 */
1090 struct GNUNET_CONTAINER_MetaData *meta;
1091
1092 /**
1093 * Client info for this search result.
1094 */
1095 void *client_info;
1096
1097 /**
1098 * ID of a job that is currently probing this results' availability
1099 * (NULL if we are not currently probing).
1100 */
1101 struct GNUNET_FS_DownloadContext *probe_ctx;
1102
1103 /**
1104 * ID of the task that will clean up the probe_ctx should it not
1105 * complete on time (and that will need to be cancelled if we clean
1106 * up the search result before then).
1107 */
1108 GNUNET_SCHEDULER_TaskIdentifier probe_cancel_task;
1109
1110 /**
1111 * When did the current probe become active?
1112 */
1113 struct GNUNET_TIME_Absolute probe_active_time;
1114
1115 /**
1116 * How much longer should we run the current probe before giving up?
1117 */
1118 struct GNUNET_TIME_Relative remaining_probe_time;
1119
1120 /**
1121 * Number of mandatory keywords for which we have NOT yet found the
1122 * search result; when this value hits zero, the search result is
1123 * given to the callback.
1124 */
1125 uint32_t mandatory_missing;
1126
1127 /**
1128 * Number of optional keywords under which this result was also
1129 * found.
1130 */
1131 uint32_t optional_support;
1132
1133 /**
1134 * Number of availability tests that have succeeded for this result.
1135 */
1136 uint32_t availability_success;
1137
1138 /**
1139 * Number of availability trials that we have performed for this
1140 * search result.
1141 */
1142 uint32_t availability_trials;
1143
1144};
1145
1146
1147/**
1148 * Information we keep for each keyword in 1188 * Information we keep for each keyword in
1149 * a keyword search. 1189 * a keyword search.
1150 */ 1190 */
@@ -1241,6 +1281,11 @@ struct GNUNET_FS_SearchContext
1241 char *serialization; 1281 char *serialization;
1242 1282
1243 /** 1283 /**
1284 * Error message (non-NULL if this operation failed).
1285 */
1286 char *emsg;
1287
1288 /**
1244 * Map that contains a "struct SearchResult" for each result that 1289 * Map that contains a "struct SearchResult" for each result that
1245 * was found in the search. The key for each entry is the XOR of 1290 * was found in the search. The key for each entry is the XOR of
1246 * the key and query in the CHK URI (as a unique identifier for the 1291 * the key and query in the CHK URI (as a unique identifier for the
diff --git a/src/fs/fs_search.c b/src/fs/fs_search.c
index efe5bf34a..a9670cb43 100644
--- a/src/fs/fs_search.c
+++ b/src/fs/fs_search.c
@@ -24,10 +24,11 @@
24 * @author Christian Grothoff 24 * @author Christian Grothoff
25 * 25 *
26 * TODO: 26 * TODO:
27 * - insert code for serialization where needed
28 * - remove *directory* with search results upon completion
29 * - centralize code that sprintf's the 'pbuf[32]' strings
27 * - add support for pushing "already seen" information 30 * - add support for pushing "already seen" information
28 * to FS service for bloomfilter (can wait) 31 * to FS service for bloomfilter (can wait)
29 * - handle availability probes (can wait)
30 * - make operations persistent (can wait)
31 */ 32 */
32 33
33#include "platform.h" 34#include "platform.h"
@@ -41,16 +42,16 @@
41 42
42 43
43/** 44/**
44 * Fill in all of the generic fields for 45 * Fill in all of the generic fields for a search event and
45 * a search event. 46 * call the callback.
46 * 47 *
47 * @param pi structure to fill in 48 * @param pi structure to fill in
48 * @param sc overall search context 49 * @param sc overall search context
49 * @return value returned by the callback 50 * @return value returned by the callback
50 */ 51 */
51static void * 52void *
52make_search_status (struct GNUNET_FS_ProgressInfo *pi, 53GNUNET_FS_search_make_status_ (struct GNUNET_FS_ProgressInfo *pi,
53 struct GNUNET_FS_SearchContext *sc) 54 struct GNUNET_FS_SearchContext *sc)
54{ 55{
55 pi->value.search.sc = sc; 56 pi->value.search.sc = sc;
56 pi->value.search.cctx 57 pi->value.search.cctx
@@ -108,7 +109,7 @@ notify_client_chk_result (struct GNUNET_FS_SearchContext *sc,
108 pi.status = GNUNET_FS_STATUS_SEARCH_RESULT; 109 pi.status = GNUNET_FS_STATUS_SEARCH_RESULT;
109 pi.value.search.specifics.result.meta = sr->meta; 110 pi.value.search.specifics.result.meta = sr->meta;
110 pi.value.search.specifics.result.uri = sr->uri; 111 pi.value.search.specifics.result.uri = sr->uri;
111 sr->client_info = make_search_status (&pi, sc); 112 sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc);
112} 113}
113 114
114 115
@@ -135,7 +136,7 @@ notify_client_chk_update (struct GNUNET_FS_SearchContext *sc,
135 = sr->availability_trials; 136 = sr->availability_trials;
136 pi.value.search.specifics.update.applicability_rank 137 pi.value.search.specifics.update.applicability_rank
137 = sr->optional_support; 138 = sr->optional_support;
138 sr->client_info = make_search_status (&pi, sc); 139 sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc);
139} 140}
140 141
141 142
@@ -183,15 +184,6 @@ get_result_present (void *cls,
183 184
184 185
185/** 186/**
186 * Start download probes for the given search result.
187 *
188 * @param sr the search result
189 */
190static void
191start_probe (struct SearchResult *sr);
192
193
194/**
195 * Signal result of last probe to client and then schedule next 187 * Signal result of last probe to client and then schedule next
196 * probe. 188 * probe.
197 */ 189 */
@@ -207,8 +199,8 @@ signal_probe_result (struct SearchResult *sr)
207 pi.value.search.specifics.update.availability_rank = sr->availability_success; 199 pi.value.search.specifics.update.availability_rank = sr->availability_success;
208 pi.value.search.specifics.update.availability_certainty = sr->availability_trials; 200 pi.value.search.specifics.update.availability_certainty = sr->availability_trials;
209 pi.value.search.specifics.update.applicability_rank = sr->optional_support; 201 pi.value.search.specifics.update.applicability_rank = sr->optional_support;
210 sr->sc->client_info = make_search_status (&pi, sr->sc); 202 sr->sc->client_info = GNUNET_FS_search_make_status_ (&pi, sr->sc);
211 start_probe (sr); 203 GNUNET_FS_search_start_probe_ (sr);
212} 204}
213 205
214 206
@@ -343,8 +335,8 @@ GNUNET_FS_search_probe_progress_ (void *cls,
343 * 335 *
344 * @param sr the search result 336 * @param sr the search result
345 */ 337 */
346static void 338void
347start_probe (struct SearchResult *sr) 339GNUNET_FS_search_start_probe_ (struct SearchResult *sr)
348{ 340{
349 uint64_t off; 341 uint64_t off;
350 uint64_t len; 342 uint64_t len;
@@ -447,7 +439,7 @@ process_ksk_result (struct GNUNET_FS_SearchContext *sc,
447 notify_client_chk_result (sc, sr); 439 notify_client_chk_result (sc, sr);
448 else 440 else
449 notify_client_chk_update (sc, sr); 441 notify_client_chk_update (sc, sr);
450 start_probe (sr); 442 GNUNET_FS_search_start_probe_ (sr);
451} 443}
452 444
453 445
@@ -510,7 +502,7 @@ process_sks_result (struct GNUNET_FS_SearchContext *sc,
510 &key, 502 &key,
511 sr, 503 sr,
512 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); 504 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
513 start_probe (sr); 505 GNUNET_FS_search_start_probe_ (sr);
514 /* notify client */ 506 /* notify client */
515 notify_client_chk_result (sc, sr); 507 notify_client_chk_result (sc, sr);
516 /* search for updates */ 508 /* search for updates */
@@ -1067,46 +1059,69 @@ search_start (struct GNUNET_FS_Handle *h,
1067 struct GNUNET_FS_SearchContext *parent) 1059 struct GNUNET_FS_SearchContext *parent)
1068{ 1060{
1069 struct GNUNET_FS_SearchContext *sc; 1061 struct GNUNET_FS_SearchContext *sc;
1070 struct GNUNET_CLIENT_Connection *client;
1071 struct GNUNET_FS_ProgressInfo pi; 1062 struct GNUNET_FS_ProgressInfo pi;
1072 size_t size; 1063
1064 sc = GNUNET_malloc (sizeof(struct GNUNET_FS_SearchContext));
1065 sc->h = h;
1066 sc->options = options;
1067 sc->uri = GNUNET_FS_uri_dup (uri);
1068 sc->anonymity = anonymity;
1069 sc->start_time = GNUNET_TIME_absolute_get ();
1070 sc->parent = parent;
1071 sc->master_result_map = GNUNET_CONTAINER_multihashmap_create (16);
1072 sc->client_info = cctx;
1073 if (NULL != parent)
1074 GNUNET_CONTAINER_DLL_insert (parent->child_head,
1075 parent->child_tail,
1076 sc);
1077 if (GNUNET_OK !=
1078 GNUNET_FS_search_start_searching_ (sc))
1079 {
1080 GNUNET_FS_uri_destroy (sc->uri);
1081 GNUNET_CONTAINER_multihashmap_destroy (sc->master_result_map);
1082 GNUNET_free (sc);
1083 return NULL;
1084 }
1085 pi.status = GNUNET_FS_STATUS_SEARCH_START;
1086 sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc);
1087 return sc;
1088}
1089
1090
1091/**
1092 * Build the request and actually initiate the search using the
1093 * GNUnet FS service.
1094 *
1095 * @param sc search context
1096 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1097 */
1098int
1099GNUNET_FS_search_start_searching_ (struct GNUNET_FS_SearchContext *sc)
1100{
1073 unsigned int i; 1101 unsigned int i;
1074 const char *keyword; 1102 const char *keyword;
1075 GNUNET_HashCode hc; 1103 GNUNET_HashCode hc;
1076 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub; 1104 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub;
1077 struct GNUNET_CRYPTO_RsaPrivateKey *pk; 1105 struct GNUNET_CRYPTO_RsaPrivateKey *pk;
1106 size_t size;
1078 1107
1079 if (GNUNET_FS_uri_test_ksk (uri)) 1108 GNUNET_assert (NULL == sc->client);
1109 if (GNUNET_FS_uri_test_ksk (sc->uri))
1080 { 1110 {
1081 size = sizeof (struct SearchMessage) * uri->data.ksk.keywordCount; 1111 size = sizeof (struct SearchMessage) * sc->uri->data.ksk.keywordCount;
1082 } 1112 }
1083 else 1113 else
1084 { 1114 {
1085 GNUNET_assert (GNUNET_FS_uri_test_sks (uri)); 1115 GNUNET_assert (GNUNET_FS_uri_test_sks (sc->uri));
1086 size = sizeof (struct SearchMessage); 1116 size = sizeof (struct SearchMessage);
1087 } 1117 }
1088 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 1118 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1089 { 1119 {
1090 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1120 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1091 _("Too many keywords specified for a single search.")); 1121 _("Too many keywords specified for a single search."));
1092 return NULL; 1122 return GNUNET_SYSERR;
1093 } 1123 }
1094 client = GNUNET_CLIENT_connect (h->sched, 1124 if (GNUNET_FS_uri_test_ksk (sc->uri))
1095 "fs",
1096 h->cfg);
1097 if (NULL == client)
1098 return NULL;
1099 sc = GNUNET_malloc (sizeof(struct GNUNET_FS_SearchContext));
1100 sc->h = h;
1101 sc->options = options;
1102 sc->uri = GNUNET_FS_uri_dup (uri);
1103 sc->anonymity = anonymity;
1104 sc->start_time = GNUNET_TIME_absolute_get ();
1105 sc->client = client;
1106 sc->parent = parent;
1107 sc->master_result_map = GNUNET_CONTAINER_multihashmap_create (16);
1108 sc->client_info = cctx;
1109 if (GNUNET_FS_uri_test_ksk (uri))
1110 { 1125 {
1111 GNUNET_assert (0 != sc->uri->data.ksk.keywordCount); 1126 GNUNET_assert (0 != sc->uri->data.ksk.keywordCount);
1112 sc->requests = GNUNET_malloc (sizeof (struct SearchRequestEntry) * 1127 sc->requests = GNUNET_malloc (sizeof (struct SearchRequestEntry) *
@@ -1130,22 +1145,23 @@ search_start (struct GNUNET_FS_Handle *h,
1130 &sc->requests[i].key); 1145 &sc->requests[i].key);
1131 } 1146 }
1132 } 1147 }
1133 if (NULL != parent) 1148 sc->client = GNUNET_CLIENT_connect (sc->h->sched,
1134 GNUNET_CONTAINER_DLL_insert (parent->child_head, 1149 "fs",
1135 parent->child_tail, 1150 sc->h->cfg);
1136 sc); 1151 if (NULL == sc->client)
1137 pi.status = GNUNET_FS_STATUS_SEARCH_START; 1152 return GNUNET_SYSERR;
1138 sc->client_info = make_search_status (&pi, sc); 1153 GNUNET_CLIENT_notify_transmit_ready (sc->client,
1139 GNUNET_CLIENT_notify_transmit_ready (client,
1140 size, 1154 size,
1141 GNUNET_CONSTANTS_SERVICE_TIMEOUT, 1155 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
1142 GNUNET_NO, 1156 GNUNET_NO,
1143 &transmit_search_request, 1157 &transmit_search_request,
1144 sc); 1158 sc);
1145 return sc; 1159 return GNUNET_OK;
1146} 1160}
1147 1161
1148 1162
1163
1164
1149/** 1165/**
1150 * Start search for content. 1166 * Start search for content.
1151 * 1167 *
@@ -1188,7 +1204,7 @@ GNUNET_FS_search_pause (struct GNUNET_FS_SearchContext *sc)
1188 // FIXME: make persistent! 1204 // FIXME: make persistent!
1189 // FIXME: should this freeze all active probes? 1205 // FIXME: should this freeze all active probes?
1190 pi.status = GNUNET_FS_STATUS_SEARCH_PAUSED; 1206 pi.status = GNUNET_FS_STATUS_SEARCH_PAUSED;
1191 sc->client_info = make_search_status (&pi, sc); 1207 sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc);
1192} 1208}
1193 1209
1194 1210
@@ -1207,7 +1223,7 @@ GNUNET_FS_search_continue (struct GNUNET_FS_SearchContext *sc)
1207 do_reconnect (sc, NULL); 1223 do_reconnect (sc, NULL);
1208 // FIXME: make persistent! 1224 // FIXME: make persistent!
1209 pi.status = GNUNET_FS_STATUS_SEARCH_CONTINUED; 1225 pi.status = GNUNET_FS_STATUS_SEARCH_CONTINUED;
1210 sc->client_info = make_search_status (&pi, sc); 1226 sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc);
1211} 1227}
1212 1228
1213 1229
@@ -1226,6 +1242,7 @@ search_result_free (void *cls,
1226{ 1242{
1227 struct GNUNET_FS_SearchContext *sc = cls; 1243 struct GNUNET_FS_SearchContext *sc = cls;
1228 struct GNUNET_FS_Handle *h = sc->h; 1244 struct GNUNET_FS_Handle *h = sc->h;
1245 char pbuf[32];
1229 struct SearchResult *sr = value; 1246 struct SearchResult *sr = value;
1230 struct GNUNET_FS_ProgressInfo pi; 1247 struct GNUNET_FS_ProgressInfo pi;
1231 1248
@@ -1233,9 +1250,21 @@ search_result_free (void *cls,
1233 pi.value.search.specifics.result_stopped.cctx = sr->client_info; 1250 pi.value.search.specifics.result_stopped.cctx = sr->client_info;
1234 pi.value.search.specifics.result_stopped.meta = sr->meta; 1251 pi.value.search.specifics.result_stopped.meta = sr->meta;
1235 pi.value.search.specifics.result_stopped.uri = sr->uri; 1252 pi.value.search.specifics.result_stopped.uri = sr->uri;
1236 sr->client_info = make_search_status (&pi, sc); 1253 sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc);
1237 GNUNET_break (NULL == sr->client_info); 1254 GNUNET_break (NULL == sr->client_info);
1238 1255 if (sr->serialization != NULL)
1256 {
1257 GNUNET_snprintf (pbuf,
1258 sizeof (pbuf),
1259 "%s%s%s",
1260 "search-results",
1261 DIR_SEPARATOR_STR,
1262 sc->serialization);
1263 GNUNET_FS_remove_sync_file_ (sc->h,
1264 pbuf,
1265 sr->serialization);
1266 GNUNET_free (sr->serialization);
1267 }
1239 GNUNET_FS_uri_destroy (sr->uri); 1268 GNUNET_FS_uri_destroy (sr->uri);
1240 GNUNET_CONTAINER_meta_data_destroy (sr->meta); 1269 GNUNET_CONTAINER_meta_data_destroy (sr->meta);
1241 if (sr->probe_ctx != NULL) 1270 if (sr->probe_ctx != NULL)
@@ -1274,7 +1303,7 @@ GNUNET_FS_search_stop (struct GNUNET_FS_SearchContext *sc)
1274 &search_result_free, 1303 &search_result_free,
1275 sc); 1304 sc);
1276 pi.status = GNUNET_FS_STATUS_SEARCH_STOPPED; 1305 pi.status = GNUNET_FS_STATUS_SEARCH_STOPPED;
1277 sc->client_info = make_search_status (&pi, sc); 1306 sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc);
1278 GNUNET_break (NULL == sc->client_info); 1307 GNUNET_break (NULL == sc->client_info);
1279 if (sc->task != GNUNET_SCHEDULER_NO_TASK) 1308 if (sc->task != GNUNET_SCHEDULER_NO_TASK)
1280 GNUNET_SCHEDULER_cancel (sc->h->sched, 1309 GNUNET_SCHEDULER_cancel (sc->h->sched,
@@ -1289,6 +1318,7 @@ GNUNET_FS_search_stop (struct GNUNET_FS_SearchContext *sc)
1289 GNUNET_CONTAINER_multihashmap_destroy (sc->requests[i].results); 1318 GNUNET_CONTAINER_multihashmap_destroy (sc->requests[i].results);
1290 } 1319 }
1291 GNUNET_free_non_null (sc->requests); 1320 GNUNET_free_non_null (sc->requests);
1321 GNUNET_free_non_null (sc->emsg);
1292 GNUNET_FS_uri_destroy (sc->uri); 1322 GNUNET_FS_uri_destroy (sc->uri);
1293 GNUNET_free (sc); 1323 GNUNET_free (sc);
1294} 1324}