From 0d4f151374efb1972361c40b6624bf4fd0e3fcaa Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 11 Feb 2019 21:07:26 +0100 Subject: externalizing secushare logic --- configure.ac | 13 - pkgconfig/Makefile.am | 9 +- pkgconfig/gnunetmulticast.pc.in | 12 - pkgconfig/gnunetpsyc.pc.in | 12 - pkgconfig/gnunetpsycstore.pc.in | 12 - pkgconfig/gnunetsocial.pc.in | 12 - po/POTFILES.in | 130 +- src/Makefile.am | 8 +- src/include/Makefile.am | 13 +- src/include/gnunet_multicast_service.h | 925 ----- src/include/gnunet_psyc_env.h | 340 -- src/include/gnunet_psyc_message.h | 278 -- src/include/gnunet_psyc_service.h | 1364 -------- src/include/gnunet_psyc_slicer.h | 378 --- src/include/gnunet_psyc_util_lib.h | 53 - src/include/gnunet_psycstore_plugin.h | 383 --- src/include/gnunet_psycstore_service.h | 701 ---- src/include/gnunet_social_service.h | 1344 -------- src/multicast/.gitignore | 7 - src/multicast/Makefile.am | 79 - src/multicast/gnunet-multicast.c | 79 - src/multicast/gnunet-service-multicast.c | 2234 ------------ src/multicast/multicast.conf.in | 22 - src/multicast/multicast.h | 303 -- src/multicast/multicast_api.c | 1399 -------- src/multicast/test_multicast.c | 758 ----- src/multicast/test_multicast.conf | 56 - src/multicast/test_multicast_2peers.c | 520 --- src/multicast/test_multicast_line.conf | 63 - src/multicast/test_multicast_multipeer.c | 643 ---- src/multicast/test_multicast_star.conf | 64 - src/psyc/.gitignore | 2 - src/psyc/Makefile.am | 77 - src/psyc/gnunet-service-psyc.c | 2860 ---------------- src/psyc/psyc.conf.in | 12 - src/psyc/psyc.h | 178 - src/psyc/psyc_api.c | 1584 --------- src/psyc/psyc_test_lib.h | 67 - src/psyc/test_psyc.c | 1018 ------ src/psyc/test_psyc.conf | 28 - src/psyc/test_psyc2.c | 284 -- src/psyc/test_psyc_api_join.c | 282 -- src/psycstore/.gitignore | 5 - src/psycstore/Makefile.am | 155 - src/psycstore/gnunet-service-psycstore.c | 1049 ------ src/psycstore/plugin_psycstore_mysql.c | 1960 ----------- src/psycstore/plugin_psycstore_postgres.c | 1530 --------- src/psycstore/plugin_psycstore_sqlite.c | 1948 ----------- src/psycstore/psycstore.conf.in | 28 - src/psycstore/psycstore.h | 520 --- src/psycstore/psycstore_api.c | 1285 ------- src/psycstore/test_plugin_psycstore.c | 532 --- src/psycstore/test_plugin_psycstore_mysql.conf | 7 - src/psycstore/test_plugin_psycstore_postgres.conf | 2 - src/psycstore/test_plugin_psycstore_sqlite.conf | 2 - src/psycstore/test_psycstore.c | 586 ---- src/psycstore/test_psycstore.conf | 8 - src/psycutil/.gitignore | 1 - src/psycutil/Makefile.am | 45 - src/psycutil/psyc_env.c | 196 -- src/psycutil/psyc_message.c | 1355 -------- src/psycutil/psyc_slicer.c | 711 ---- src/psycutil/test_psyc_env.c | 96 - src/social/.gitignore | 3 - src/social/Makefile.am | 79 - src/social/gnunet-service-social.c | 3760 --------------------- src/social/gnunet-social.c | 1411 -------- src/social/social.conf.in | 15 - src/social/social.h | 292 -- src/social/social_api.c | 2827 ---------------- src/social/test_social.c | 1449 -------- src/social/test_social.conf | 19 - 72 files changed, 62 insertions(+), 40420 deletions(-) delete mode 100644 pkgconfig/gnunetmulticast.pc.in delete mode 100644 pkgconfig/gnunetpsyc.pc.in delete mode 100644 pkgconfig/gnunetpsycstore.pc.in delete mode 100644 pkgconfig/gnunetsocial.pc.in delete mode 100644 src/include/gnunet_multicast_service.h delete mode 100644 src/include/gnunet_psyc_env.h delete mode 100644 src/include/gnunet_psyc_message.h delete mode 100644 src/include/gnunet_psyc_service.h delete mode 100644 src/include/gnunet_psyc_slicer.h delete mode 100644 src/include/gnunet_psyc_util_lib.h delete mode 100644 src/include/gnunet_psycstore_plugin.h delete mode 100644 src/include/gnunet_psycstore_service.h delete mode 100644 src/include/gnunet_social_service.h delete mode 100644 src/multicast/.gitignore delete mode 100644 src/multicast/Makefile.am delete mode 100644 src/multicast/gnunet-multicast.c delete mode 100644 src/multicast/gnunet-service-multicast.c delete mode 100644 src/multicast/multicast.conf.in delete mode 100644 src/multicast/multicast.h delete mode 100644 src/multicast/multicast_api.c delete mode 100644 src/multicast/test_multicast.c delete mode 100644 src/multicast/test_multicast.conf delete mode 100644 src/multicast/test_multicast_2peers.c delete mode 100644 src/multicast/test_multicast_line.conf delete mode 100644 src/multicast/test_multicast_multipeer.c delete mode 100644 src/multicast/test_multicast_star.conf delete mode 100644 src/psyc/.gitignore delete mode 100644 src/psyc/Makefile.am delete mode 100644 src/psyc/gnunet-service-psyc.c delete mode 100644 src/psyc/psyc.conf.in delete mode 100644 src/psyc/psyc.h delete mode 100644 src/psyc/psyc_api.c delete mode 100644 src/psyc/psyc_test_lib.h delete mode 100644 src/psyc/test_psyc.c delete mode 100644 src/psyc/test_psyc.conf delete mode 100644 src/psyc/test_psyc2.c delete mode 100644 src/psyc/test_psyc_api_join.c delete mode 100644 src/psycstore/.gitignore delete mode 100644 src/psycstore/Makefile.am delete mode 100644 src/psycstore/gnunet-service-psycstore.c delete mode 100644 src/psycstore/plugin_psycstore_mysql.c delete mode 100644 src/psycstore/plugin_psycstore_postgres.c delete mode 100644 src/psycstore/plugin_psycstore_sqlite.c delete mode 100644 src/psycstore/psycstore.conf.in delete mode 100644 src/psycstore/psycstore.h delete mode 100644 src/psycstore/psycstore_api.c delete mode 100644 src/psycstore/test_plugin_psycstore.c delete mode 100644 src/psycstore/test_plugin_psycstore_mysql.conf delete mode 100644 src/psycstore/test_plugin_psycstore_postgres.conf delete mode 100644 src/psycstore/test_plugin_psycstore_sqlite.conf delete mode 100644 src/psycstore/test_psycstore.c delete mode 100644 src/psycstore/test_psycstore.conf delete mode 100644 src/psycutil/.gitignore delete mode 100644 src/psycutil/Makefile.am delete mode 100644 src/psycutil/psyc_env.c delete mode 100644 src/psycutil/psyc_message.c delete mode 100644 src/psycutil/psyc_slicer.c delete mode 100644 src/psycutil/test_psyc_env.c delete mode 100644 src/social/.gitignore delete mode 100644 src/social/Makefile.am delete mode 100644 src/social/gnunet-service-social.c delete mode 100644 src/social/gnunet-social.c delete mode 100644 src/social/social.conf.in delete mode 100644 src/social/social.h delete mode 100644 src/social/social_api.c delete mode 100644 src/social/test_social.c delete mode 100644 src/social/test_social.conf diff --git a/configure.ac b/configure.ac index 3dd1ce3e6..38182599f 100644 --- a/configure.ac +++ b/configure.ac @@ -1766,8 +1766,6 @@ src/include/Makefile src/integration-tests/Makefile src/json/Makefile src/hostlist/Makefile -src/multicast/Makefile -src/multicast/multicast.conf src/my/Makefile src/mysql/Makefile src/namecache/Makefile @@ -1787,11 +1785,6 @@ src/peerinfo-tool/Makefile src/peerstore/Makefile src/peerstore/peerstore.conf src/pq/Makefile -src/psycutil/Makefile -src/psyc/Makefile -src/psyc/psyc.conf -src/psycstore/Makefile -src/psycstore/psycstore.conf src/pt/Makefile src/regex/Makefile src/regex/regex.conf @@ -1805,8 +1798,6 @@ src/scalarproduct/Makefile src/scalarproduct/scalarproduct.conf src/set/Makefile src/set/set.conf -src/social/Makefile -src/social/social.conf src/sq/Makefile src/statistics/Makefile src/statistics/statistics.conf @@ -1850,21 +1841,17 @@ pkgconfig/gnunetgns.pc pkgconfig/gnunethello.pc pkgconfig/gnunetidentity.pc pkgconfig/gnunetmicrophone.pc -pkgconfig/gnunetmulticast.pc pkgconfig/gnunetmysql.pc pkgconfig/gnunetnamestore.pc pkgconfig/gnunetnat.pc pkgconfig/gnunetnse.pc pkgconfig/gnunetpeerinfo.pc pkgconfig/gnunetpq.pc -pkgconfig/gnunetpsyc.pc -pkgconfig/gnunetpsycstore.pc pkgconfig/gnunetregex.pc pkgconfig/gnunetrevocation.pc pkgconfig/gnunetrps.pc pkgconfig/gnunetscalarproduct.pc pkgconfig/gnunetset.pc -pkgconfig/gnunetsocial.pc pkgconfig/gnunetspeaker.pc pkgconfig/gnunetstatistics.pc pkgconfig/gnunettestbed.pc diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am index 3a3102f0a..04243a608 100644 --- a/pkgconfig/Makefile.am +++ b/pkgconfig/Makefile.am @@ -19,14 +19,11 @@ pcfiles = \ gnunetidentity.pc \ gnunetcadet.pc \ gnunetmicrophone.pc \ - gnunetmulticast.pc \ gnunetmysql.pc \ gnunetnamestore.pc \ gnunetnat.pc \ gnunetnse.pc \ gnunetpeerinfo.pc \ - gnunetpsyc.pc \ - gnunetpsycstore.pc \ gnunetregex.pc \ gnunetrevocation.pc \ gnunetrps.pc \ @@ -38,7 +35,7 @@ pcfiles = \ gnunettesting.pc \ gnunettransport.pc \ gnunetutil.pc \ - gnunetvpn.pc + gnunetvpn.pc all-local: $(pcfiles) @@ -95,9 +92,7 @@ EXTRA_DIST = \ gnunettransport.pc.in \ gnunettun.pc.in \ gnunetutil.pc.in \ - gnunetvpn.pc.in + gnunetvpn.pc.in CLEANFILES = $(pcfiles) AM_CPPFLAGS = -I$(top_srcdir)/src/include - - diff --git a/pkgconfig/gnunetmulticast.pc.in b/pkgconfig/gnunetmulticast.pc.in deleted file mode 100644 index 204555519..000000000 --- a/pkgconfig/gnunetmulticast.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: GNUnet MULTICAST -Description: library to multicast messages to a group of peers -URL: https://gnunet.org -Version: @VERSION@ -Requires: -Libs: -L${libdir} -lgnunetmulticast -Cflags: -I${includedir} diff --git a/pkgconfig/gnunetpsyc.pc.in b/pkgconfig/gnunetpsyc.pc.in deleted file mode 100644 index 9cfabdf83..000000000 --- a/pkgconfig/gnunetpsyc.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: GNUnet PSYC -Description: library for PSYC multicast channel management -URL: https://gnunet.org -Version: @VERSION@ -Requires: -Libs: -L${libdir} -lgnunetpsyc -Cflags: -I${includedir} diff --git a/pkgconfig/gnunetpsycstore.pc.in b/pkgconfig/gnunetpsycstore.pc.in deleted file mode 100644 index 765abdc5b..000000000 --- a/pkgconfig/gnunetpsycstore.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: GNUnet PSYCSTORE -Description: library to for persistent storage of PSYC messages -URL: https://gnunet.org -Version: @VERSION@ -Requires: -Libs: -L${libdir} -lgnunetpsycstore -Cflags: -I${includedir} diff --git a/pkgconfig/gnunetsocial.pc.in b/pkgconfig/gnunetsocial.pc.in deleted file mode 100644 index 5ea9c6a26..000000000 --- a/pkgconfig/gnunetsocial.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: GNUnet Social -Description: library for social interactions -URL: https://gnunet.org -Version: @VERSION@ -Requires: -Libs: -L${libdir} -lgnunetsocial -Cflags: -I${includedir} diff --git a/po/POTFILES.in b/po/POTFILES.in index 0ee48fcde..fb1e0e25e 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -4,14 +4,6 @@ src/arm/arm_monitor_api.c src/arm/gnunet-arm.c src/arm/gnunet-service-arm.c src/arm/mockup-service.c -src/ats-tests/ats-testing-experiment.c -src/ats-tests/ats-testing-log.c -src/ats-tests/ats-testing-preferences.c -src/ats-tests/ats-testing-traffic.c -src/ats-tests/ats-testing.c -src/ats-tests/gnunet-ats-sim.c -src/ats-tests/gnunet-solver-eval.c -src/ats-tool/gnunet-ats.c src/ats/ats_api2_application.c src/ats/ats_api2_transport.c src/ats/ats_api_connectivity.c @@ -19,10 +11,10 @@ src/ats/ats_api_performance.c src/ats/ats_api_scanner.c src/ats/ats_api_scheduling.c src/ats/gnunet-ats-solver-eval.c -src/ats/gnunet-service-ats-new.c -src/ats/gnunet-service-ats.c src/ats/gnunet-service-ats_addresses.c +src/ats/gnunet-service-ats.c src/ats/gnunet-service-ats_connectivity.c +src/ats/gnunet-service-ats-new.c src/ats/gnunet-service-ats_normalization.c src/ats/gnunet-service-ats_performance.c src/ats/gnunet-service-ats_plugins.c @@ -34,6 +26,14 @@ src/ats/plugin_ats2_simple.c src/ats/plugin_ats_mlp.c src/ats/plugin_ats_proportional.c src/ats/plugin_ats_ril.c +src/ats-tests/ats-testing.c +src/ats-tests/ats-testing-experiment.c +src/ats-tests/ats-testing-log.c +src/ats-tests/ats-testing-preferences.c +src/ats-tests/ats-testing-traffic.c +src/ats-tests/gnunet-ats-sim.c +src/ats-tests/gnunet-solver-eval.c +src/ats-tool/gnunet-ats.c src/auction/gnunet-auction-create.c src/auction/gnunet-auction-info.c src/auction/gnunet-auction-join.c @@ -50,8 +50,8 @@ src/cadet/cadet_api_list_peers.c src/cadet/cadet_api_list_tunnels.c src/cadet/cadet_test_lib.c src/cadet/desirability_table.c -src/cadet/gnunet-cadet-profiler.c src/cadet/gnunet-cadet.c +src/cadet/gnunet-cadet-profiler.c src/cadet/gnunet-service-cadet.c src/cadet/gnunet-service-cadet_channel.c src/cadet/gnunet-service-cadet_connection.c @@ -67,15 +67,15 @@ src/consensus/gnunet-service-consensus.c src/consensus/plugin_block_consensus.c src/conversation/conversation_api.c src/conversation/conversation_api_call.c -src/conversation/gnunet-conversation-test.c src/conversation/gnunet-conversation.c -src/conversation/gnunet-helper-audio-playback-gst.c +src/conversation/gnunet-conversation-test.c +src/conversation/gnunet_gst.c +src/conversation/gnunet_gst_test.c src/conversation/gnunet-helper-audio-playback.c -src/conversation/gnunet-helper-audio-record-gst.c +src/conversation/gnunet-helper-audio-playback-gst.c src/conversation/gnunet-helper-audio-record.c +src/conversation/gnunet-helper-audio-record-gst.c src/conversation/gnunet-service-conversation.c -src/conversation/gnunet_gst.c -src/conversation/gnunet_gst_test.c src/conversation/microphone.c src/conversation/plugin_gnsrecord_conversation.c src/conversation/speaker.c @@ -111,6 +111,7 @@ src/dht/dht_api.c src/dht/dht_test_lib.c src/dht/gnunet-dht-get.c src/dht/gnunet-dht-monitor.c +src/dht/gnunet_dht_profiler.c src/dht/gnunet-dht-put.c src/dht/gnunet-service-dht.c src/dht/gnunet-service-dht_clients.c @@ -119,7 +120,6 @@ src/dht/gnunet-service-dht_hello.c src/dht/gnunet-service-dht_neighbours.c src/dht/gnunet-service-dht_nse.c src/dht/gnunet-service-dht_routing.c -src/dht/gnunet_dht_profiler.c src/dht/plugin_block_dht.c src/dns/dns_api.c src/dns/gnunet-dns-monitor.c @@ -133,8 +133,8 @@ src/dv/gnunet-dv.c src/dv/gnunet-service-dv.c src/dv/plugin_transport_dv.c src/exit/gnunet-daemon-exit.c -src/exit/gnunet-helper-exit-windows.c src/exit/gnunet-helper-exit.c +src/exit/gnunet-helper-exit-windows.c src/fragmentation/defragmentation.c src/fragmentation/fragmentation.c src/fs/fs_api.c @@ -159,8 +159,8 @@ src/fs/gnunet-auto-share.c src/fs/gnunet-daemon-fsprofiler.c src/fs/gnunet-directory.c src/fs/gnunet-download.c -src/fs/gnunet-fs-profiler.c src/fs/gnunet-fs.c +src/fs/gnunet-fs-profiler.c src/fs/gnunet-helper-fs-publish.c src/fs/gnunet-publish.c src/fs/gnunet-search.c @@ -180,10 +180,10 @@ src/gns/gns_tld_api.c src/gns/gnunet-bcd.c src/gns/gnunet-dns2gns.c src/gns/gnunet-gns-benchmark.c +src/gns/gnunet-gns.c src/gns/gnunet-gns-helper-service-w32.c src/gns/gnunet-gns-import.c src/gns/gnunet-gns-proxy.c -src/gns/gnunet-gns.c src/gns/gnunet-service-gns.c src/gns/gnunet-service-gns_interceptor.c src/gns/gnunet-service-gns_resolver.c @@ -191,19 +191,19 @@ src/gns/nss/nss_gns.c src/gns/nss/nss_gns_query.c src/gns/plugin_block_gns.c src/gns/plugin_gnsrecord_gns.c -src/gns/w32nsp-install.c -src/gns/w32nsp-resolve.c -src/gns/w32nsp-uninstall.c -src/gns/w32nsp.c src/gnsrecord/gnsrecord.c src/gnsrecord/gnsrecord_crypto.c src/gnsrecord/gnsrecord_misc.c src/gnsrecord/gnsrecord_serialization.c src/gnsrecord/plugin_gnsrecord_dns.c +src/gns/w32nsp.c +src/gns/w32nsp-install.c +src/gns/w32nsp-resolve.c +src/gns/w32nsp-uninstall.c src/hello/address.c src/hello/gnunet-hello.c -src/hello/hello-ng.c src/hello/hello.c +src/hello/hello-ng.c src/hostlist/gnunet-daemon-hostlist.c src/hostlist/gnunet-daemon-hostlist_client.c src/hostlist/gnunet-daemon-hostlist_server.c @@ -216,9 +216,6 @@ src/json/json_generator.c src/json/json_gnsrecord.c src/json/json_helper.c src/json/json_mhd.c -src/multicast/gnunet-multicast.c -src/multicast/gnunet-service-multicast.c -src/multicast/multicast_api.c src/my/my.c src/my/my_query_helper.c src/my/my_result_helper.c @@ -229,8 +226,8 @@ src/namecache/namecache_api.c src/namecache/plugin_namecache_flat.c src/namecache/plugin_namecache_postgres.c src/namecache/plugin_namecache_sqlite.c -src/namestore/gnunet-namestore-fcfsd.c src/namestore/gnunet-namestore.c +src/namestore/gnunet-namestore-fcfsd.c src/namestore/gnunet-service-namestore.c src/namestore/gnunet-zoneimport.c src/namestore/namestore_api.c @@ -245,10 +242,10 @@ src/nat-auto/gnunet-service-nat-auto.c src/nat-auto/gnunet-service-nat-auto_legacy.c src/nat-auto/nat_auto_api.c src/nat-auto/nat_auto_api_test.c -src/nat/gnunet-helper-nat-client-windows.c src/nat/gnunet-helper-nat-client.c -src/nat/gnunet-helper-nat-server-windows.c +src/nat/gnunet-helper-nat-client-windows.c src/nat/gnunet-helper-nat-server.c +src/nat/gnunet-helper-nat-server-windows.c src/nat/gnunet-nat.c src/nat/gnunet-service-nat.c src/nat/gnunet-service-nat_externalip.c @@ -257,16 +254,16 @@ src/nat/gnunet-service-nat_mini.c src/nat/gnunet-service-nat_stun.c src/nat/nat_api.c src/nat/nat_api_stun.c -src/nse/gnunet-nse-profiler.c src/nse/gnunet-nse.c +src/nse/gnunet-nse-profiler.c src/nse/gnunet-service-nse.c src/nse/nse_api.c src/nt/nt.c -src/peerinfo-tool/gnunet-peerinfo.c -src/peerinfo-tool/gnunet-peerinfo_plugins.c src/peerinfo/gnunet-service-peerinfo.c src/peerinfo/peerinfo_api.c src/peerinfo/peerinfo_api_notify.c +src/peerinfo-tool/gnunet-peerinfo.c +src/peerinfo-tool/gnunet-peerinfo_plugins.c src/peerstore/gnunet-peerstore.c src/peerstore/gnunet-service-peerstore.c src/peerstore/peerstore_api.c @@ -280,16 +277,6 @@ src/pq/pq_exec.c src/pq/pq_prepare.c src/pq/pq_query_helper.c src/pq/pq_result_helper.c -src/psyc/gnunet-service-psyc.c -src/psyc/psyc_api.c -src/psycstore/gnunet-service-psycstore.c -src/psycstore/plugin_psycstore_mysql.c -src/psycstore/plugin_psycstore_postgres.c -src/psycstore/plugin_psycstore_sqlite.c -src/psycstore/psycstore_api.c -src/psycutil/psyc_env.c -src/psycutil/psyc_message.c -src/psycutil/psyc_slicer.c src/pt/gnunet-daemon-pt.c src/reclaim-attribute/plugin_reclaim_attribute_gnuid.c src/reclaim-attribute/reclaim_attribute.c @@ -312,6 +299,7 @@ src/regex/regex_internal_dht.c src/regex/regex_test_graph.c src/regex/regex_test_lib.c src/regex/regex_test_random.c +src/rest/gnunet-rest-server.c src/rest-plugins/json_reclaim.c src/rest-plugins/oidc_helper.c src/rest-plugins/plugin_rest_copying.c @@ -322,28 +310,27 @@ src/rest-plugins/plugin_rest_namestore.c src/rest-plugins/plugin_rest_openid_connect.c src/rest-plugins/plugin_rest_peerinfo.c src/rest-plugins/plugin_rest_reclaim.c -src/rest/gnunet-rest-server.c src/rest/rest.c src/revocation/gnunet-revocation.c src/revocation/gnunet-service-revocation.c src/revocation/plugin_block_revocation.c src/revocation/revocation_api.c -src/rps/gnunet-rps-profiler.c src/rps/gnunet-rps.c +src/rps/gnunet-rps-profiler.c src/rps/gnunet-service-rps.c src/rps/gnunet-service-rps_custommap.c src/rps/gnunet-service-rps_sampler.c src/rps/gnunet-service-rps_sampler_elem.c src/rps/gnunet-service-rps_view.c +src/rps/rps_api.c src/rps/rps-sampler_client.c src/rps/rps-sampler_common.c src/rps/rps-test_util.c -src/rps/rps_api.c src/scalarproduct/gnunet-scalarproduct.c -src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c -src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c src/scalarproduct/gnunet-service-scalarproduct_alice.c src/scalarproduct/gnunet-service-scalarproduct_bob.c +src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c +src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c src/scalarproduct/scalarproduct_api.c src/secretsharing/gnunet-secretsharing-profiler.c src/secretsharing/gnunet-service-secretsharing.c @@ -359,9 +346,6 @@ src/set/ibf.c src/set/ibf_sim.c src/set/plugin_block_set_test.c src/set/set_api.c -src/social/gnunet-service-social.c -src/social/gnunet-social.c -src/social/social_api.c src/sq/sq.c src/sq/sq_exec.c src/sq/sq_prepare.c @@ -372,16 +356,15 @@ src/statistics/gnunet-statistics.c src/statistics/statistics_api.c src/template/gnunet-service-template.c src/template/gnunet-template.c -src/testbed-logger/gnunet-service-testbed-logger.c -src/testbed-logger/testbed_logger_api.c src/testbed/generate-underlay-topology.c src/testbed/gnunet-daemon-latency-logger.c src/testbed/gnunet-daemon-testbed-blacklist.c src/testbed/gnunet-daemon-testbed-underlay.c src/testbed/gnunet-helper-testbed.c +src/testbed/gnunet_mpi_test.c src/testbed/gnunet-service-test-barriers.c -src/testbed/gnunet-service-testbed.c src/testbed/gnunet-service-testbed_barriers.c +src/testbed/gnunet-service-testbed.c src/testbed/gnunet-service-testbed_cache.c src/testbed/gnunet-service-testbed_connectionpool.c src/testbed/gnunet-service-testbed_cpustatus.c @@ -389,19 +372,20 @@ src/testbed/gnunet-service-testbed_links.c src/testbed/gnunet-service-testbed_meminfo.c src/testbed/gnunet-service-testbed_oc.c src/testbed/gnunet-service-testbed_peers.c -src/testbed/gnunet-testbed-profiler.c -src/testbed/gnunet_mpi_test.c src/testbed/gnunet_testbed_mpi_spawn.c -src/testbed/testbed_api.c +src/testbed/gnunet-testbed-profiler.c +src/testbed-logger/gnunet-service-testbed-logger.c +src/testbed-logger/testbed_logger_api.c src/testbed/testbed_api_barriers.c +src/testbed/testbed_api.c src/testbed/testbed_api_hosts.c src/testbed/testbed_api_operations.c src/testbed/testbed_api_peers.c src/testbed/testbed_api_sd.c src/testbed/testbed_api_services.c src/testbed/testbed_api_statistics.c -src/testbed/testbed_api_test.c src/testbed/testbed_api_testbed.c +src/testbed/testbed_api_test.c src/testbed/testbed_api_topology.c src/testbed/testbed_api_underlay.c src/testing/gnunet-testing.c @@ -413,29 +397,29 @@ src/transport/gnunet-communicator-tcp.c src/transport/gnunet-communicator-udp.c src/transport/gnunet-communicator-unix.c src/transport/gnunet-helper-transport-bluetooth.c -src/transport/gnunet-helper-transport-wlan-dummy.c src/transport/gnunet-helper-transport-wlan.c +src/transport/gnunet-helper-transport-wlan-dummy.c src/transport/gnunet-service-tng.c -src/transport/gnunet-service-transport.c src/transport/gnunet-service-transport_ats.c +src/transport/gnunet-service-transport.c src/transport/gnunet-service-transport_hello.c src/transport/gnunet-service-transport_manipulation.c src/transport/gnunet-service-transport_neighbours.c src/transport/gnunet-service-transport_plugins.c src/transport/gnunet-service-transport_validation.c +src/transport/gnunet-transport.c src/transport/gnunet-transport-certificate-creation.c src/transport/gnunet-transport-profiler.c src/transport/gnunet-transport-wlan-receiver.c src/transport/gnunet-transport-wlan-sender.c -src/transport/gnunet-transport.c src/transport/plugin_transport_http_client.c src/transport/plugin_transport_http_common.c src/transport/plugin_transport_http_server.c src/transport/plugin_transport_smtp.c src/transport/plugin_transport_tcp.c src/transport/plugin_transport_template.c -src/transport/plugin_transport_udp.c src/transport/plugin_transport_udp_broadcasting.c +src/transport/plugin_transport_udp.c src/transport/plugin_transport_unix.c src/transport/plugin_transport_wlan.c src/transport/plugin_transport_xt.c @@ -444,11 +428,6 @@ src/transport/tcp_connection_legacy.c src/transport/tcp_server_legacy.c src/transport/tcp_server_mst_legacy.c src/transport/tcp_service_legacy.c -src/transport/transport-testing-filenames.c -src/transport/transport-testing-loggers.c -src/transport/transport-testing-main.c -src/transport/transport-testing-send.c -src/transport/transport-testing.c src/transport/transport_api2_communication.c src/transport/transport_api2_core.c src/transport/transport_api2_monitor.c @@ -460,6 +439,11 @@ src/transport/transport_api_manipulation.c src/transport/transport_api_monitor_peers.c src/transport/transport_api_monitor_plugins.c src/transport/transport_api_offer_hello.c +src/transport/transport-testing.c +src/transport/transport-testing-filenames.c +src/transport/transport-testing-loggers.c +src/transport/transport-testing-main.c +src/transport/transport-testing-send.c src/util/bandwidth.c src/util/benchmark.c src/util/bio.c @@ -472,8 +456,8 @@ src/util/configuration_loader.c src/util/container_bloomfilter.c src/util/container_heap.c src/util/container_meta_data.c -src/util/container_multihashmap.c src/util/container_multihashmap32.c +src/util/container_multihashmap.c src/util/container_multipeermap.c src/util/container_multishortmap.c src/util/crypto_abe.c @@ -495,15 +479,15 @@ src/util/dnsparser.c src/util/dnsstub.c src/util/getopt.c src/util/getopt_helpers.c -src/util/gnunet-config-diff.c src/util/gnunet-config.c +src/util/gnunet-config-diff.c src/util/gnunet-ecc.c src/util/gnunet-helper-w32-console.c src/util/gnunet-resolver.c src/util/gnunet-scrypt.c src/util/gnunet-service-resolver.c -src/util/gnunet-timeout-w32.c src/util/gnunet-timeout.c +src/util/gnunet-timeout-w32.c src/util/gnunet-uri.c src/util/helper.c src/util/load.c @@ -532,13 +516,13 @@ src/util/tun.c src/util/w32cat.c src/util/win.c src/util/winproc.c -src/vpn/gnunet-helper-vpn-windows.c src/vpn/gnunet-helper-vpn.c +src/vpn/gnunet-helper-vpn-windows.c src/vpn/gnunet-service-vpn.c src/vpn/gnunet-vpn.c src/vpn/vpn_api.c -src/zonemaster/gnunet-service-zonemaster-monitor.c src/zonemaster/gnunet-service-zonemaster.c +src/zonemaster/gnunet-service-zonemaster-monitor.c src/fs/fs_api.h src/include/compat.h src/include/gnunet_common.h diff --git a/src/Makefile.am b/src/Makefile.am index 5fd65141b..03738e4ed 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,13 +11,7 @@ endif if HAVE_EXPERIMENTAL EXP_DIR = \ - rps \ - multicast \ - psycutil \ - psycstore \ - psyc \ - social -# dv (FTBFS) + rps if HAVE_ABE if HAVE_JSON EXP_DIR += \ diff --git a/src/include/Makefile.am b/src/include/Makefile.am index 195cac075..69ea7c83e 100644 --- a/src/include/Makefile.am +++ b/src/include/Makefile.am @@ -69,8 +69,8 @@ gnunetinclude_HEADERS = \ gnunet_hello_lib.h \ gnunet_helper_lib.h \ gnunet_identity_service.h \ - gnunet_abe_lib.h \ - gnunet_reclaim_attribute_lib.h \ + gnunet_abe_lib.h \ + gnunet_reclaim_attribute_lib.h \ gnunet_reclaim_attribute_plugin.h \ gnunet_reclaim_plugin.h \ gnunet_reclaim_service.h \ @@ -78,7 +78,6 @@ gnunetinclude_HEADERS = \ gnunet_load_lib.h \ gnunet_cadet_service.h \ gnunet_microphone_lib.h \ - gnunet_multicast_service.h \ gnunet_mst_lib.h \ gnunet_mq_lib.h \ gnunet_my_lib.h \ @@ -101,13 +100,6 @@ gnunetinclude_HEADERS = \ gnunet_peerstore_service.h \ gnunet_plugin_lib.h \ gnunet_pq_lib.h \ - gnunet_psycstore_plugin.h \ - gnunet_psycstore_service.h \ - gnunet_psyc_service.h \ - gnunet_psyc_util_lib.h \ - gnunet_psyc_env.h \ - gnunet_psyc_message.h \ - gnunet_psyc_slicer.h \ gnunet_program_lib.h \ gnunet_protocols.h \ gnunet_resolver_service.h \ @@ -122,7 +114,6 @@ gnunetinclude_HEADERS = \ gnunet_set_service.h \ gnunet_signal_lib.h \ gnunet_signatures.h \ - gnunet_social_service.h \ gnunet_socks.h \ gnunet_speaker_lib.h \ gnunet_sq_lib.h \ diff --git a/src/include/gnunet_multicast_service.h b/src/include/gnunet_multicast_service.h deleted file mode 100644 index 58fca0b2e..000000000 --- a/src/include/gnunet_multicast_service.h +++ /dev/null @@ -1,925 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012, 2013 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later -*/ - -/** - * @author Gabor X Toth - * @author Christian Grothoff - * - * @file - * Multicast service; multicast messaging via CADET - * - * @defgroup multicast Multicast service - * Multicast messaging via CADET. - * @{ - */ - -#ifndef GNUNET_MULTICAST_SERVICE_H -#define GNUNET_MULTICAST_SERVICE_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "gnunet_util_lib.h" -#include "gnunet_transport_service.h" - -/** - * Version number of GNUnet-multicast API. - */ -#define GNUNET_MULTICAST_VERSION 0x00000000 - -/** - * Opaque handle for a multicast group member. - */ -struct GNUNET_MULTICAST_Member; - -/** - * Handle for the origin of a multicast group. - */ -struct GNUNET_MULTICAST_Origin; - - -enum GNUNET_MULTICAST_MessageFlags -{ - /** - * First fragment of a message. - */ - GNUNET_MULTICAST_MESSAGE_FIRST_FRAGMENT = 1 << 0, - - /** - * Last fragment of a message. - */ - GNUNET_MULTICAST_MESSAGE_LAST_FRAGMENT = 1 << 1, - - /** - * OR'ed flags if message is not fragmented. - */ - GNUNET_MULTICAST_MESSAGE_NOT_FRAGMENTED - = GNUNET_MULTICAST_MESSAGE_FIRST_FRAGMENT - | GNUNET_MULTICAST_MESSAGE_LAST_FRAGMENT, - - /** - * Historic message, used only locally when replaying messages from local - * storage. - */ - GNUNET_MULTICAST_MESSAGE_HISTORIC = 1 << 30 - -}; - - -GNUNET_NETWORK_STRUCT_BEGIN - -/** - * Header of a multicast message fragment. - * - * This format is public as the replay mechanism must replay message fragments using the - * same format. This is needed as we want to integrity-check message fragments within - * the multicast layer to avoid multicasting mal-formed messages. - */ -struct GNUNET_MULTICAST_MessageHeader -{ - - /** - * Header for all multicast message fragments from the origin. - */ - struct GNUNET_MessageHeader header; - - /** - * Number of hops this message fragment has taken since the origin. - * - * Helpful to determine shortest paths to the origin among honest peers for - * unicast requests from members. Updated at each hop and thus not signed and - * not secure. - */ - uint32_t hop_counter GNUNET_PACKED; - - /** - * ECC signature of the message fragment. - * - * Signature must match the public key of the multicast group. - */ - struct GNUNET_CRYPTO_EddsaSignature signature; - - /** - * Purpose for the signature and size of the signed data. - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - - /** - * Number of the message fragment, monotonically increasing starting from 1. - */ - uint64_t fragment_id GNUNET_PACKED; - - /** - * Byte offset of this @e fragment of the @e message. - */ - uint64_t fragment_offset GNUNET_PACKED; - - /** - * Number of the message this fragment belongs to. - * - * Set in GNUNET_MULTICAST_origin_to_all(). - */ - uint64_t message_id GNUNET_PACKED; - - /** - * Counter that monotonically increases whenever a member parts the group. - * - * Set in GNUNET_MULTICAST_origin_to_all(). - * - * It has significance in case of replay requests: when a member has missed - * messages and gets a replay request: in this case if the @a group_generation - * is still the same before and after the missed messages, it means that no - * @e join or @e part operations happened during the missed messages. - */ - uint64_t group_generation GNUNET_PACKED; - - /** - * Flags for this message fragment. - * - * @see enum GNUNET_MULTICAST_MessageFlags - */ - uint32_t flags GNUNET_PACKED; - - /* Followed by message body. */ -}; - - -/** - * Header of a request from a member to the origin. - */ -struct GNUNET_MULTICAST_RequestHeader -{ - /** - * Header for all requests from a member to the origin. - */ - struct GNUNET_MessageHeader header; - - /** - * Public key of the sending member. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; - - /** - * ECC signature of the request fragment. - * - * Signature must match the public key of the multicast group. - */ - struct GNUNET_CRYPTO_EcdsaSignature signature; - - /** - * Purpose for the signature and size of the signed data. - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - - /** - * Number of the request fragment. - * Monotonically increasing from 1. - */ - uint64_t fragment_id GNUNET_PACKED; - - /** - * Byte offset of this @e fragment of the @e request. - */ - uint64_t fragment_offset GNUNET_PACKED; - - /** - * Number of the request this fragment belongs to. - * - * Set in GNUNET_MULTICAST_origin_to_all(). - */ - uint64_t request_id GNUNET_PACKED; - - /** - * Flags for this request. - */ - enum GNUNET_MULTICAST_MessageFlags flags GNUNET_PACKED; - - /* Followed by request body. */ -}; - -GNUNET_NETWORK_STRUCT_END - - -/** - * Maximum size of a multicast message fragment. - */ -#define GNUNET_MULTICAST_FRAGMENT_MAX_SIZE (63 * 1024) - -#define GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD \ - (GNUNET_MULTICAST_FRAGMENT_MAX_SIZE \ - - sizeof (struct GNUNET_MULTICAST_MessageHeader)) - - -/** - * Handle that identifies a join request. - * - * Used to match calls to #GNUNET_MULTICAST_JoinRequestCallback to the - * corresponding calls to #GNUNET_MULTICAST_join_decision(). - */ -struct GNUNET_MULTICAST_JoinHandle; - - -/** - * Function to call with the decision made for a join request. - * - * Must be called once and only once in response to an invocation of the - * #GNUNET_MULTICAST_JoinRequestCallback. - * - * @param jh - * Join request handle. - * @param is_admitted - * #GNUNET_YES if the join is approved, - * #GNUNET_NO if it is disapproved, - * #GNUNET_SYSERR if we cannot answer the request. - * @param relay_count - * Number of relays given. - * @param relays - * Array of suggested peers that might be useful relays to use - * when joining the multicast group (essentially a list of peers that - * are already part of the multicast group and might thus be willing - * to help with routing). If empty, only this local peer (which must - * be the multicast origin) is a good candidate for building the - * multicast tree. Note that it is unnecessary to specify our own - * peer identity in this array. - * @param join_resp - * Message to send in response to the joining peer; - * can also be used to redirect the peer to a different group at the - * application layer; this response is to be transmitted to the - * peer that issued the request even if admission is denied. - */ -struct GNUNET_MULTICAST_ReplayHandle * -GNUNET_MULTICAST_join_decision (struct GNUNET_MULTICAST_JoinHandle *jh, - int is_admitted, - uint16_t relay_count, - const struct GNUNET_PeerIdentity *relays, - const struct GNUNET_MessageHeader *join_resp); - - -/** - * Method called whenever another peer wants to join the multicast group. - * - * Implementations of this function must call GNUNET_MULTICAST_join_decision() - * with the decision. - * - * @param cls - * Closure. - * @param member_pub_key - * Public key of the member requesting join. - * @param join_msg - * Application-dependent join message from the new member. - * @param jh - * Join handle to pass to GNUNET_MULTICAST_join_decison(). - */ -typedef void -(*GNUNET_MULTICAST_JoinRequestCallback) (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, - const struct GNUNET_MessageHeader *join_msg, - struct GNUNET_MULTICAST_JoinHandle *jh); - - -/** - * Method called to inform about the decision in response to a join request. - * - * If @a is_admitted is not #GNUNET_YES, then the multicast service disconnects - * the client and the multicast member handle returned by - * GNUNET_MULTICAST_member_join() is invalidated. - * - * @param cls - * Closure. - * @param is_admitted - * #GNUNET_YES or #GNUNET_NO or #GNUNET_SYSERR - * @param peer - * The peer we are connected to and the join decision is from. - * @param relay_count - * Number of peers in the @a relays array. - * @param relays - * Peer identities of members of the group, which serve as relays - * and can be used to join the group at. If empty, only the origin can - * be used to connect to the group. - * @param join_msg - * Application-dependent join message from the origin. - */ -typedef void -(*GNUNET_MULTICAST_JoinDecisionCallback) (void *cls, - int is_admitted, - const struct GNUNET_PeerIdentity *peer, - uint16_t relay_count, - const struct GNUNET_PeerIdentity *relays, - const struct GNUNET_MessageHeader *join_msg); - - -/** - * Function called whenever a group member has transmitted a request - * to the origin (other than joining or leaving). - * - * FIXME: need to distinguish between origin cancelling a message (some fragments - * were sent, then the rest 'discarded') and the case where we got disconnected; - * right now, both would mean 'msg' is NULL, but they could be quite different... - * So the semantics from the receiver side of - * GNUNET_MULTICAST_member_to_origin_cancel() are not clear here. Maybe we - * should do something with the flags in this case? - * - * @param cls - * Closure (set from GNUNET_MULTICAST_origin_start). - * @param sender - * Identity of the sender. - * @param req - * Request to the origin. - * @param flags - * Flags for the request. - */ -typedef void -(*GNUNET_MULTICAST_RequestCallback) (void *cls, - const struct GNUNET_MULTICAST_RequestHeader *req); - - -/** - * Function called whenever a group member is receiving a message fragment from - * the origin. - * - * If admission to the group is denied, this function is called once with the - * response of the @e origin (as given to GNUNET_MULTICAST_join_decision()) and - * then a second time with NULL to indicate that the connection failed for good. - * - * FIXME: need to distinguish between origin cancelling a message (some fragments - * were sent, then the rest 'discarded') and the case where we got disconnected; - * right now, both would mean 'msg' is NULL, but they could be quite different... - * So the semantics from the receiver side of - * GNUNET_MULTICAST_origin_to_all_cancel() are not clear here. - * - * @param cls - * Closure (set from GNUNET_MULTICAST_member_join()) - * @param msg - * Message from the origin, NULL if the origin shut down - * (or we were kicked out, and we should thus call - * GNUNET_MULTICAST_member_part() next) - */ -typedef void -(*GNUNET_MULTICAST_MessageCallback) (void *cls, - const struct GNUNET_MULTICAST_MessageHeader *msg); - - -/** - * Opaque handle to a replay request from the multicast service. - */ -struct GNUNET_MULTICAST_ReplayHandle; - - -/** - * Functions with this signature are called whenever the multicast service needs - * a message fragment to be replayed by fragment_id. - * - * Implementations of this function MUST call GNUNET_MULTICAST_replay() ONCE - * (with a message or an error); however, if the origin is destroyed or the - * group is left, the replay handle must no longer be used. - * - * @param cls - * Closure (set from GNUNET_MULTICAST_origin_start() - * or GNUNET_MULTICAST_member_join()). - * @param member_pub_key - * The member requesting replay. - * @param fragment_id - * Which message fragment should be replayed. - * @param flags - * Flags for the replay. - * @param rh - * Handle to pass to message transmit function. - */ -typedef void -(*GNUNET_MULTICAST_ReplayFragmentCallback) (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, - uint64_t fragment_id, - uint64_t flags, - struct GNUNET_MULTICAST_ReplayHandle *rh); - -/** - * Functions with this signature are called whenever the multicast service needs - * a message fragment to be replayed by message_id and fragment_offset. - * - * Implementations of this function MUST call GNUNET_MULTICAST_replay() ONCE - * (with a message or an error); however, if the origin is destroyed or the - * group is left, the replay handle must no longer be used. - * - * @param cls - * Closure (set from GNUNET_MULTICAST_origin_start() - * or GNUNET_MULTICAST_member_join()). - * @param member_pub_key - * The member requesting replay. - * @param message_id - * Which message should be replayed. - * @param fragment_offset - * Offset of the fragment within of @a message_id to be replayed. - * @param flags - * Flags for the replay. - * @param rh - * Handle to pass to message transmit function. - */ -typedef void -(*GNUNET_MULTICAST_ReplayMessageCallback) (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, - uint64_t message_id, - uint64_t fragment_offset, - uint64_t flags, - struct GNUNET_MULTICAST_ReplayHandle *rh); - - -/** - * Possible error codes during replay. - */ -enum GNUNET_MULTICAST_ReplayErrorCode -{ - - /** - * Everything is fine. - */ - GNUNET_MULTICAST_REC_OK = 0, - - /** - * Message fragment not found in the message store. - * - * Either discarded if it is too old, or not arrived yet if this member has - * missed some messages. - */ - GNUNET_MULTICAST_REC_NOT_FOUND = 1, - - /** - * Fragment ID counter was larger than the highest counter this - * replay function has ever encountered; thus it is likely the - * origin never sent it and we're at the HEAD of the multicast - * stream as far as this node is concerned. - * - * FIXME: needed? - */ - GNUNET_MULTICAST_REC_PAST_HEAD = 2, - - /** - * Access is denied to the requested fragment, membership test did not pass. - */ - GNUNET_MULTICAST_REC_ACCESS_DENIED = 3, - - /** - * Internal error (i.e. database error). Try some other peer. - */ - GNUNET_MULTICAST_REC_INTERNAL_ERROR = 4 - -}; - - -/** - * Replay a message fragment for the multicast group. - * - * @param rh - * Replay handle identifying which replay operation was requested. - * @param msg - * Replayed message fragment, NULL if not found / an error occurred. - * @param ec - * Error code. See enum GNUNET_MULTICAST_ReplayErrorCode - * If not #GNUNET_MULTICAST_REC_OK, the replay handle is invalidated. - */ -void -GNUNET_MULTICAST_replay_response (struct GNUNET_MULTICAST_ReplayHandle *rh, - const struct GNUNET_MessageHeader *msg, - enum GNUNET_MULTICAST_ReplayErrorCode ec); - - -/** - * Indicate the end of the replay session. - * - * Invalidates the replay handle. - * - * @param rh Replay session to end. - */ -void -GNUNET_MULTICAST_replay_response_end (struct GNUNET_MULTICAST_ReplayHandle *rh); - - -/** - * Function called to provide data for a transmission for a replay. - * - * @see GNUNET_MULTICAST_replay2() - */ -typedef int -(*GNUNET_MULTICAST_ReplayTransmitNotify) (void *cls, - size_t *data_size, - void *data); - - -/** - * Replay a message for the multicast group. - * - * @param rh - * Replay handle identifying which replay operation was requested. - * @param notify - * Function to call to get the message. - * @param notify_cls - * Closure for @a notify. - */ -void -GNUNET_MULTICAST_replay_response2 (struct GNUNET_MULTICAST_ReplayHandle *rh, - GNUNET_MULTICAST_ReplayTransmitNotify notify, - void *notify_cls); - - -/** - * Start a multicast group. - * - * Peers that issue GNUNET_MULTICAST_member_join() can transmit a join request - * to either an existing group member or to the origin. If the joining is - * approved, the member is cleared for @e replay and will begin to receive - * messages transmitted to the group. If joining is disapproved, the failed - * candidate will be given a response. Members in the group can send messages - * to the origin. - * - * TODO: This function could optionally offer to advertise the origin in the - * P2P overlay network(where?) under the respective public key so that other - * peers can find an alternate PeerId to join it. Higher level protocols may - * however provide other means of solving the problem of the offline host - * (see secushare specs about that) and therefore merely need a way to provide - * a list of possible PeerIds. - * - * @param cfg - * Configuration to use. - * @param priv_key - * ECC key that will be used to sign messages for this - * multicast session; public key is used to identify the multicast group; - * @param max_fragment_id - * Maximum fragment ID already sent to the group. - * 0 for a new group. - * @param join_request_cb - * Function called to approve / disapprove joining of a peer. - * @param replay_frag_cb - * Function that can be called to replay a message fragment. - * @param replay_msg_cb - * Function that can be called to replay a message. - * @param request_cb - * Function called with message fragments from group members. - * @param message_cb - * Function called with the message fragments sent to the - * network by GNUNET_MULTICAST_origin_to_all(). These message fragments - * should be stored for answering replay requests later. - * @param cls - * Closure for the various callbacks that follow. - * - * @return Handle for the origin, NULL on error. - */ -struct GNUNET_MULTICAST_Origin * -GNUNET_MULTICAST_origin_start (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_CRYPTO_EddsaPrivateKey *priv_key, - uint64_t max_fragment_id, - GNUNET_MULTICAST_JoinRequestCallback join_request_cb, - GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb, - GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb, - GNUNET_MULTICAST_RequestCallback request_cb, - GNUNET_MULTICAST_MessageCallback message_cb, - void *cls); - -/** - * Function called to provide data for a transmission from the origin to all - * members. - * - * Note that returning #GNUNET_OK or #GNUNET_SYSERR (but not #GNUNET_NO) - * invalidates the respective transmission handle. - * - * @param cls - * Closure. - * @param[in,out] data_size - * Initially set to the number of bytes available in - * @a data, should be set to the number of bytes written to data. - * @param[out] data - * Where to write the body of the message to give to the - * method. The function must copy at most @a data_size bytes to @a data. - * - * @return #GNUNET_SYSERR on error (fatal, aborts transmission) - * #GNUNET_NO on success, if more data is to be transmitted later. - * Should be used if @a data_size was not big enough to take all the - * data. If 0 is returned in @a data_size the transmission is paused, - * and can be resumed with GNUNET_MULTICAST_origin_to_all_resume(). - * #GNUNET_YES if this completes the transmission (all data supplied) - * @deprecated should move to MQ-style API! - */ -typedef int -(*GNUNET_MULTICAST_OriginTransmitNotify) (void *cls, - size_t *data_size, - void *data); - - -/** - * Handle for a request to send a message to all multicast group members - * (from the origin). - */ -struct GNUNET_MULTICAST_OriginTransmitHandle; - - -/** - * Send a message to the multicast group. - * - * @param origin - * Handle to the multicast group. - * @param message_id - * Application layer ID for the message. Opaque to multicast. - * @param group_generation - * Group generation of the message. Documented in - * struct GNUNET_MULTICAST_MessageHeader. - * @param notify - * Function to call to get the message. - * @param notify_cls - * Closure for @a notify. - * - * @return NULL on error (i.e. request already pending). - * @deprecated should move to MQ-style API! - */ -struct GNUNET_MULTICAST_OriginTransmitHandle * -GNUNET_MULTICAST_origin_to_all (struct GNUNET_MULTICAST_Origin *origin, - uint64_t message_id, - uint64_t group_generation, - GNUNET_MULTICAST_OriginTransmitNotify notify, - void *notify_cls); - - - -/** - * Resume message transmission to multicast group. - * - * @param th Transmission to cancel. - */ -void -GNUNET_MULTICAST_origin_to_all_resume (struct GNUNET_MULTICAST_OriginTransmitHandle *th); - - -/** - * Cancel request for message transmission to multicast group. - * - * @param th Transmission to cancel. - */ -void -GNUNET_MULTICAST_origin_to_all_cancel (struct GNUNET_MULTICAST_OriginTransmitHandle *th); - - -/** - * Stop a multicast group. - * - * @param origin Multicast group to stop. - */ -void -GNUNET_MULTICAST_origin_stop (struct GNUNET_MULTICAST_Origin *origin, - GNUNET_ContinuationCallback stop_cb, - void *stop_cls); - - -/** - * Join a multicast group. - * - * The entity joining is always the local peer. Further information about the - * candidate can be provided in @a join_msg. If the join fails, the - * @a message_cb is invoked with a (failure) response and then with NULL. If - * the join succeeds, outstanding (state) messages and ongoing multicast - * messages will be given to the @a message_cb until the member decides to part - * the group. The @a mem_test_cb and @a replay_cb functions may be called at - * anytime by the multicast service to support relaying messages to other - * members of the group. - * - * @param cfg - * Configuration to use. - * @param group_key - * ECC public key that identifies the group to join. - * @param member_pub_key - * ECC key that identifies the member - * and used to sign requests sent to the origin. - * @param origin - * Peer ID of the origin to send unicast requsets to. If NULL, - * unicast requests are sent back via multiple hops on the reverse path - * of multicast messages. - * @param relay_count - * Number of peers in the @a relays array. - * @param relays - * Peer identities of members of the group, which serve as relays - * and can be used to join the group at. and send the @a join_request to. - * If empty, the @a join_request is sent directly to the @a origin. - * @param join_msg - * Application-dependent join message to be passed to the peer @a origin. - * @param join_request_cb - * Function called to approve / disapprove joining of a peer. - * @param join_decision_cb - * Function called to inform about the join decision. - * @param replay_frag_cb - * Function that can be called to replay message fragments - * this peer already knows from this group. NULL if this - * client is unable to support replay. - * @param replay_msg_cb - * Function that can be called to replay message fragments - * this peer already knows from this group. NULL if this - * client is unable to support replay. - * @param message_cb - * Function to be called for all message fragments we - * receive from the group, excluding those our @a replay_cb - * already has. - * @param cls - * Closure for callbacks. - * - * @return Handle for the member, NULL on error. - */ -struct GNUNET_MULTICAST_Member * -GNUNET_MULTICAST_member_join (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_CRYPTO_EddsaPublicKey *group_key, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *member_pub_key, - const struct GNUNET_PeerIdentity *origin, - uint16_t relay_count, - const struct GNUNET_PeerIdentity *relays, - const struct GNUNET_MessageHeader *join_request, - GNUNET_MULTICAST_JoinRequestCallback join_request_cb, - GNUNET_MULTICAST_JoinDecisionCallback join_decision_cb, - GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb, - GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb, - GNUNET_MULTICAST_MessageCallback message_cb, - void *cls); - -/** - * Handle for a replay request. - */ -struct GNUNET_MULTICAST_MemberReplayHandle; - - -/** - * Request a fragment to be replayed by fragment ID. - * - * Useful if messages below the @e max_known_fragment_id given when joining are - * needed and not known to the client. - * - * @param member - * Membership handle. - * @param fragment_id - * ID of a message fragment that this client would like to see replayed. - * @param flags - * Additional flags for the replay request. - * It is used and defined by GNUNET_MULTICAST_ReplayFragmentCallback - * - * @return Replay request handle, NULL on error. - */ -struct GNUNET_MULTICAST_MemberReplayHandle * -GNUNET_MULTICAST_member_replay_fragment (struct GNUNET_MULTICAST_Member *member, - uint64_t fragment_id, - uint64_t flags); - - -/** - * Request a message fr to be replayed. - * - * Useful if messages below the @e max_known_fragment_id given when joining are - * needed and not known to the client. - * - * @param member - * Membership handle. - * @param message_id - * ID of the message this client would like to see replayed. - * @param fragment_offset - * Offset of the fragment within the message to replay. - * @param flags - * Additional flags for the replay request. - * It is used & defined by GNUNET_MULTICAST_ReplayMessageCallback - * - * @return Replay request handle, NULL on error. - */ -struct GNUNET_MULTICAST_MemberReplayHandle * -GNUNET_MULTICAST_member_replay_message (struct GNUNET_MULTICAST_Member *member, - uint64_t message_id, - uint64_t fragment_offset, - uint64_t flags); - - -/** - * Cancel a replay request. - * - * @param rh - * Request to cancel. - */ -void -GNUNET_MULTICAST_member_replay_cancel (struct GNUNET_MULTICAST_MemberReplayHandle *rh); - - -/** - * Part a multicast group. - * - * Disconnects from all group members and invalidates the @a member handle. - * - * An application-dependent part message can be transmitted beforehand using - * #GNUNET_MULTICAST_member_to_origin()) - * - * @param member - * Membership handle. - */ -void -GNUNET_MULTICAST_member_part (struct GNUNET_MULTICAST_Member *member, - GNUNET_ContinuationCallback part_cb, - void *part_cls); - - -/** - * Function called to provide data for a transmission from a member to the origin. - * - * Note that returning #GNUNET_OK or #GNUNET_SYSERR (but not #GNUNET_NO) - * invalidates the respective transmission handle. - * - * @param cls - * Closure. - * @param[in,out] data_size - * Initially set to the number of bytes available in - * @a data, should be set to the number of bytes written to data. - * @param[out] data - * Where to write the body of the message to give to the - * method. The function must copy at most @a data_size bytes to @a data. - * - * @return #GNUNET_SYSERR on error (fatal, aborts transmission) - * #GNUNET_NO on success, if more data is to be transmitted later. - * Should be used if @a data_size was not big enough to take all the - * data. If 0 is returned in @a data_size the transmission is paused, - * and can be resumed with GNUNET_MULTICAST_member_to_origin_resume(). - * #GNUNET_YES if this completes the transmission (all data supplied) - * @deprecated should move to MQ-style API! - */ -typedef int -(*GNUNET_MULTICAST_MemberTransmitNotify) (void *cls, - size_t *data_size, - void *data); - - -/** - * Handle for a message to be delivered from a member to the origin. - */ -struct GNUNET_MULTICAST_MemberTransmitHandle; - - -/** - * Send a message to the origin of the multicast group. - * - * @param member - * Membership handle. - * @param request_id - * Application layer ID for the request. Opaque to multicast. - * @param notify - * Callback to call to get the message. - * @param notify_cls - * Closure for @a notify. - * - * @return Handle to cancel request, NULL on error (i.e. request already pending). - * @deprecated should move to MQ-style API! - */ -struct GNUNET_MULTICAST_MemberTransmitHandle * -GNUNET_MULTICAST_member_to_origin (struct GNUNET_MULTICAST_Member *member, - uint64_t request_id, - GNUNET_MULTICAST_MemberTransmitNotify notify, - void *notify_cls); - - -/** - * Resume message transmission to origin. - * - * @param th - * Transmission to cancel. - */ -void -GNUNET_MULTICAST_member_to_origin_resume (struct GNUNET_MULTICAST_MemberTransmitHandle *th); - - -/** - * Cancel request for message transmission to origin. - * - * @param th - * Transmission to cancel. - */ -void -GNUNET_MULTICAST_member_to_origin_cancel (struct GNUNET_MULTICAST_MemberTransmitHandle *th); - - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef GNUNET_MULTICAST_SERVICE_H */ -#endif - -/** @} */ /* end of group */ diff --git a/src/include/gnunet_psyc_env.h b/src/include/gnunet_psyc_env.h deleted file mode 100644 index 0d878cb96..000000000 --- a/src/include/gnunet_psyc_env.h +++ /dev/null @@ -1,340 +0,0 @@ -/* - * This file is part of GNUnet. - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @author Gabor X Toth - * - * @file - * PSYC Environment library - * - * @defgroup psyc-util-env PSYC Utilities library: Environment - * Environment data structure operations for PSYC and Social messages. - * - * Library providing operations for the @e environment of - * PSYC and Social messages, and for (de)serializing variable values. - * - * @{ - */ - - -#ifndef GNUNET_PSYC_ENV_H -#define GNUNET_PSYC_ENV_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - - -/** - * Possible operations on PSYC state (persistent) and transient variables (per message). - */ -enum GNUNET_PSYC_Operator -{ - /** - * Set value of a transient variable. - */ - GNUNET_PSYC_OP_SET = ':', - - /** - * Assign value for a persistent state variable. - * - * If an assigned value is NULL, the variable is deleted. - */ - GNUNET_PSYC_OP_ASSIGN = '=', - - /** - * Augment state variable. - * - * Used for appending strings, adding numbers, and adding new items to a list or dictionary. - */ - GNUNET_PSYC_OP_AUGMENT = '+', - - /** - * Diminish state variable. - * - * Used for subtracting numbers, and removing items from a list or dictionary. - */ - GNUNET_PSYC_OP_DIMINISH = '-', - - /** - * Update state variable. - * - * Used for modifying a single item of a list or dictionary. - */ - GNUNET_PSYC_OP_UPDATE = '@', -}; - - -/** - * PSYC variable types. - */ -enum GNUNET_PSYC_Type -{ - GNUNET_PSYC_TYPE_DATA = 0, - GNUNET_PSYC_TYPE_NUMBER, - GNUNET_PSYC_TYPE_LIST, - GNUNET_PSYC_TYPE_DICT -}; - - -/** - * PSYC state modifier. - */ -struct GNUNET_PSYC_Modifier -{ - /** - * State operation. - */ - enum GNUNET_PSYC_Operator oper; - - /** - * Variable name. - */ - const char *name; - - /** - * Size of @a value. - */ - size_t value_size; - - /** - * Value of variable. - */ - const void *value; - - /** - * Next modifier. - */ - struct GNUNET_PSYC_Modifier *next; - - /** - * Previous modifier. - */ - struct GNUNET_PSYC_Modifier *prev; -}; - - -/** - * Environment for a message. - * - * Contains modifiers. - */ -struct GNUNET_PSYC_Environment; - - -/** - * Create an environment. - * - * @return A newly allocated environment. - */ -struct GNUNET_PSYC_Environment * -GNUNET_PSYC_env_create (); - - -/** - * Add a modifier to the environment. - * - * @param env The environment. - * @param oper Operation to perform. - * @param name Name of the variable. - * @param value Value of the variable. - * @param value_size Size of @a value. - */ -void -GNUNET_PSYC_env_add (struct GNUNET_PSYC_Environment *env, - enum GNUNET_PSYC_Operator oper, const char *name, - const void *value, size_t value_size); - - -/** - * Get the first modifier of the environment. - */ -struct GNUNET_PSYC_Modifier * -GNUNET_PSYC_env_head (const struct GNUNET_PSYC_Environment *env); - - - -/** - * Get the last modifier of the environment. - */ -struct GNUNET_PSYC_Modifier * -GNUNET_PSYC_env_tail (const struct GNUNET_PSYC_Environment *env); - - -/** - * Remove a modifier from the environment. - */ -void -GNUNET_PSYC_env_remove (struct GNUNET_PSYC_Environment *env, - struct GNUNET_PSYC_Modifier *mod); - - -/** - * Remove a modifier at the beginning of the environment. - */ -int -GNUNET_PSYC_env_shift (struct GNUNET_PSYC_Environment *env, - enum GNUNET_PSYC_Operator *oper, const char **name, - const void **value, size_t *value_size); - - -/** - * Iterator for modifiers in the environment. - * - * @param cls Closure. - * @param mod Modifier. - * - * @return #GNUNET_YES to continue iterating, - * #GNUNET_NO to stop. - */ -typedef int -(*GNUNET_PSYC_Iterator) (void *cls, enum GNUNET_PSYC_Operator oper, - const char *name, const char *value, - uint32_t value_size); - - -/** - * Iterate through all modifiers in the environment. - * - * @param env The environment. - * @param it Iterator. - * @param it_cls Closure for iterator. - */ -void -GNUNET_PSYC_env_iterate (const struct GNUNET_PSYC_Environment *env, - GNUNET_PSYC_Iterator it, void *it_cls); - - -/** - * Get the number of modifiers in the environment. - * - * @param env The environment. - * - * @return Number of modifiers. - */ -size_t -GNUNET_PSYC_env_get_count (const struct GNUNET_PSYC_Environment *env); - - -/** - * Destroy an environment. - * - * @param env The environment to destroy. - */ -void -GNUNET_PSYC_env_destroy (struct GNUNET_PSYC_Environment *env); - - -/** - * Get the type of variable. - * - * @param name Name of the variable. - * - * @return Variable type. - */ -enum GNUNET_PSYC_Type -GNUNET_PSYC_var_get_type (char *name); - - -/** - * Perform an operation on a variable. - * - * @param name Name of variable. - * @param current_value Current value of variable. - * @param current_value_size Size of @a current_value. - * @param oper Operator. - * @param args Arguments for the operation. - * @param args_size Size of @a args. - * @param return_value Return value. - * @param return_value_size Size of @a return_value. - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -int -GNUNET_PSYC_operation (char *name, void *current_value, size_t current_value_size, - enum GNUNET_PSYC_Operator oper, void *args, size_t args_size, - void **return_value, size_t *return_value_size); - - -/** - * Get the variable's value as an integer. - * - * @param size Size of value. - * @param value Raw value of variable. - * @param[out] number Value converted to a 64-bit integer. - * - * @return #GNUNET_OK on success, #GNUNET_SYSERR if an error occurred (e.g. the value is invalid). - */ -int -GNUNET_PSYC_value_to_number (size_t size, const void *value, int64_t *number); - - -/** - * Get the variable's value as a dictionary. - * - * @param size Size of value. - * @param value Raw value of variable. - * @param[out] dict A newly created hashmap holding the elements of the dictionary. - * - * @return #GNUNET_OK on success, #GNUNET_SYSERR if an error occurred (e.g. the value is invalid). - */ -int -GNUNET_PSYC_value_to_dict (size_t size, const void *value, struct GNUNET_CONTAINER_MultiHashMap **dict); - - -/** - * Create a PSYC variable value from an integer. - * - * @param number The number to convert. - * @param[out] value_size Size of returned value. - * - * @return A newly allocated value or NULL on error. - */ -void * -GNUNET_PSYC_value_from_number (int64_t number, size_t *value_size); - - -/** - * Create a PSYC variable value from a dictionary. - * - * @param dict The dict to convert. - * @param[out] value_size Size of returned value. - * - * @return A newly allocated value or NULL on error. - */ -void * -GNUNET_PSYC_value_from_dict (struct GNUNET_CONTAINER_MultiHashMap *dict, size_t *value_size); - - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef GNUNET_PSYC_ENV_H */ -#endif - -/** @} */ /* end of group */ diff --git a/src/include/gnunet_psyc_message.h b/src/include/gnunet_psyc_message.h deleted file mode 100644 index d0cf9cc6a..000000000 --- a/src/include/gnunet_psyc_message.h +++ /dev/null @@ -1,278 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012, 2013 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later -*/ - -/** - * @author Gabor X Toth - * - * @file - * PSYC message utilities; receiving/transmitting/logging PSYC messages - * - * @defgroup psyc-util-message PSYC Utilities library: Messages - * Receiving, transmitting, logging PSYC messages. - * @{ - */ - -#ifndef GNUNET_PSYC_MESSAGE_H -#define GNUNET_PSYC_MESSAGE_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - - -#include "gnunet_util_lib.h" -#include "gnunet_psyc_util_lib.h" -#include "gnunet_psyc_service.h" - - -/** - * Create a PSYC message. - * - * @param method_name - * PSYC method for the message. - * @param env - * Environment for the message. - * @param data - * Data payload for the message. - * @param data_size - * Size of @a data. - * - * @return Message header with size information, - * followed by the message parts. - * - * FIXME: arg order - */ -struct GNUNET_PSYC_Message * -GNUNET_PSYC_message_create (const char *method_name, - const struct GNUNET_PSYC_Environment *env, - const void *data, - size_t data_size); - -/** - * Parse PSYC message. - * - * @param msg - * The PSYC message to parse. - * @param env - * The environment for the message with a list of modifiers. - * @param[out] method_name - * Pointer to the method name inside @a pmsg. - * @param[out] data - * Pointer to data inside @a pmsg. - * @param[out] data_size - * Size of @data is written here. - * - * @return #GNUNET_OK on success, - * #GNUNET_SYSERR on parse error. - * - * FIXME: arg order - */ -int -GNUNET_PSYC_message_parse (const struct GNUNET_PSYC_MessageHeader *msg, - const char **method_name, - struct GNUNET_PSYC_Environment *env, - const void **data, - uint16_t *data_size); - - -void -GNUNET_PSYC_log_message (enum GNUNET_ErrorType kind, - const struct GNUNET_MessageHeader *msg); - - -struct GNUNET_PSYC_TransmitHandle; - -/** - * Create a transmission handle. - */ -struct GNUNET_PSYC_TransmitHandle * -GNUNET_PSYC_transmit_create (struct GNUNET_MQ_Handle *mq); - - -/** - * Destroy a transmission handle. - */ -void -GNUNET_PSYC_transmit_destroy (struct GNUNET_PSYC_TransmitHandle *tmit); - - -/** - * Transmit a message. - * - * @param tmit - * Transmission handle. - * @param method_name - * Which method should be invoked. - * @param env - * Environment for the message. - * Should stay available until the first call to notify_data. - * Can be NULL if there are no modifiers or @a notify_mod is - * provided instead. - * @param notify_mod - * Function to call to obtain modifiers. - * Can be NULL if there are no modifiers or @a env is provided instead. - * @param notify_data - * Function to call to obtain fragments of the data. - * @param notify_cls - * Closure for @a notify_mod and @a notify_data. - * @param flags - * Flags for the message being transmitted. - * - * @return #GNUNET_OK if the transmission was started. - * #GNUNET_SYSERR if another transmission is already going on. - */ -int -GNUNET_PSYC_transmit_message (struct GNUNET_PSYC_TransmitHandle *tmit, - const char *method_name, - const struct GNUNET_PSYC_Environment *env, - GNUNET_PSYC_TransmitNotifyModifier notify_mod, - GNUNET_PSYC_TransmitNotifyData notify_data, - void *notify_cls, - uint32_t flags); - - -/** - * Resume transmission. - * - * @param tmit Transmission handle. - */ -void -GNUNET_PSYC_transmit_resume (struct GNUNET_PSYC_TransmitHandle *tmit); - - -/** - * Abort transmission request. - * - * @param tmit Transmission handle. - */ -void -GNUNET_PSYC_transmit_cancel (struct GNUNET_PSYC_TransmitHandle *tmit); - - -/** - * Got acknowledgement of a transmitted message part, continue transmission. - * - * @param tmit Transmission handle. - */ -void -GNUNET_PSYC_transmit_got_ack (struct GNUNET_PSYC_TransmitHandle *tmit); - - -struct GNUNET_PSYC_ReceiveHandle; - - -/** - * Create handle for receiving messages. - */ -struct GNUNET_PSYC_ReceiveHandle * -GNUNET_PSYC_receive_create (GNUNET_PSYC_MessageCallback message_cb, - GNUNET_PSYC_MessagePartCallback message_part_cb, - void *cb_cls); - - -/** - * Destroy handle for receiving messages. - */ -void -GNUNET_PSYC_receive_destroy (struct GNUNET_PSYC_ReceiveHandle *recv); - - -/** - * Reset stored data related to the last received message. - */ -void -GNUNET_PSYC_receive_reset (struct GNUNET_PSYC_ReceiveHandle *recv); - - -/** - * Handle incoming PSYC message. - * - * @param recv - * Receive handle. - * @param msg - * The message. - * - * @return #GNUNET_OK on success, - * #GNUNET_SYSERR on receive error. - */ -int -GNUNET_PSYC_receive_message (struct GNUNET_PSYC_ReceiveHandle *recv, - const struct GNUNET_PSYC_MessageHeader *msg); - - -/** - * Check if @a data contains a series of valid message parts. - * - * @param data_size - * Size of @a data. - * @param data - * Data. - * @param[out] first_ptype - * Type of first message part. - * @param[out] last_ptype - * Type of last message part. - * - * @return Number of message parts found in @a data. - * or GNUNET_SYSERR if the message contains invalid parts. - */ -int -GNUNET_PSYC_receive_check_parts (uint16_t data_size, const char *data, - uint16_t *first_ptype, uint16_t *last_ptype); - - -/** - * Initialize PSYC message header. - */ -void -GNUNET_PSYC_message_header_init (struct GNUNET_PSYC_MessageHeader *pmsg, - const struct GNUNET_MULTICAST_MessageHeader *mmsg, - uint32_t flags); - - -/** - * Create a new PSYC message header from a multicast message for sending it to clients. - */ -struct GNUNET_PSYC_MessageHeader * -GNUNET_PSYC_message_header_create (const struct GNUNET_MULTICAST_MessageHeader *mmsg, - uint32_t flags); - - -/** - * Create a new PSYC message header from a PSYC message. - */ -struct GNUNET_PSYC_MessageHeader * -GNUNET_PSYC_message_header_create_from_psyc (const struct GNUNET_PSYC_Message *msg); - - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef GNUNET_PSYC_MESSAGE_H */ -#endif - -/** @} */ /* end of group */ diff --git a/src/include/gnunet_psyc_service.h b/src/include/gnunet_psyc_service.h deleted file mode 100644 index 3a3131e33..000000000 --- a/src/include/gnunet_psyc_service.h +++ /dev/null @@ -1,1364 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012, 2013 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later -*/ - -/** - * @author Gabor X Toth - * @author Christian Grothoff - * - * @file - * PSYC service - * - * @defgroup psyc PSYC service - * Send/receive messages in PSYC channels and access the PSYC Store. - * - * Note that clients of this API are NOT expected to understand the PSYC message - * format, only the semantics! Parsing (and serializing) the PSYC stream format - * is done within the implementation of the libgnunetpsyc library, and this API - * deliberately exposes as little as possible of the actual data stream format - * to the application! - * - * NOTE: - * - this API does not know about PSYC's "root" and "places"; - * there is no 'root' in GNUnet-PSYC as we're decentralized; - * 'places' and 'persons' are combined within the same - * abstraction, that of a "channel". Channels are identified - * and accessed in this API using a public/private key. - * Higher-level applications should use NAMES within GNS - * to obtain public keys, and the distinction between - * 'places' and 'persons' can then be made with the help - * of the naming system (and/or conventions). - * Channels are (as in PSYC) organized into a hierarchy; each - * channel master (the one with the private key) is then - * the operator of the multicast group (its Origin in - * the terminology of the multicast API). - * - The API supports passing large amounts of data using - * 'streaming' for the argument passed to a method. State - * and variables must fit into memory and cannot be streamed - * (thus, no passing of 4 GB of data in a variable; - * once we implement this, we might want to create a - * @c \#define for the maximum size of a variable). - * - PSYC defines standard variables, methods, etc. This - * library deliberately abstracts over all of these; a - * higher-level API should combine the naming system (GNS) - * and standard methods (_converse, _notice, _request, - * _warning, _error etc) and variables (_action, _color, - * _time, etc). However, this API does take over the - * routing variables, specifically '_context' (channel), - * and '_source'. We only kind-of support '_target', as - * the target is either everyone in the group or the - * origin, and never just a single member of the group; - * for such individual messages, an application needs to - * construct an 'inbox' channel where the master (only) - * receives messages (but never forwards; private responses - * would be transmitted by joining the senders 'inbox' - * channel -- or a inbox#bob subchannel). The - * goal for all of this is to keep the abstractions in this - * API minimal: interaction with multicast, try \& slice, - * state/variable/channel management. Higher-level - * operations belong elsewhere (so maybe this API should - * be called 'PSYC-low', whereas a higher-level API - * implementing defaults for standard methods and - * variables might be called 'PSYC-std' or 'PSYC-high'. - * - * In PSYC terminology this is simply called the "PSYC - * routing layer" and the abstractions, for instance in - * psyced, are quite similar. The higher one is called - * "PSYC entity layer." In the text rendering of the - * protocol the two are separated by an empty line. See - * http://about.psyc.eu/Spec:Packet and related. --lynX - * - * @{ - */ - -#ifndef GNUNET_PSYC_SERVICE_H -#define GNUNET_PSYC_SERVICE_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "gnunet_util_lib.h" -#include "gnunet_multicast_service.h" -//Mingw work around -#ifdef MINGW - # ifndef UINT64_MAX - # define UINT64_MAX 0xffffffffffffffffULL - # endif -#endif - -/** - * Version number of GNUnet-PSYC API. - */ -#define GNUNET_PSYC_VERSION 0x00000000 - - -/** - * Policy flags for a channel. - */ -enum GNUNET_PSYC_ChannelFlags -{ - /** - * Admission must be confirmed by the master. - */ - GNUNET_PSYC_CHANNEL_ADMISSION_CONTROL = 1 << 0, - - /** - * Past messages are only available to slaves who were admitted at the time - * they were sent to the channel. - */ - GNUNET_PSYC_CHANNEL_RESTRICTED_HISTORY = 1 << 1 -}; - - -/** - * PSYC channel policies. - */ -enum GNUNET_PSYC_Policy -{ - /** - * Anyone can join the channel, without announcing their presence; - * all messages are always public and can be distributed freely. - * Joins may be announced, but this is not required. - */ - GNUNET_PSYC_CHANNEL_ANONYMOUS = 0, - - /** - * The master must approve membership to the channel, messages must only be - * distributed to current channel slaves. This includes the channel - * state as well as transient messages. - */ - GNUNET_PSYC_CHANNEL_PRIVATE - = GNUNET_PSYC_CHANNEL_ADMISSION_CONTROL - | GNUNET_PSYC_CHANNEL_RESTRICTED_HISTORY - -#if IDEAS_FOR_FUTURE - /** - * Anyone can freely join the channel (no approval required); - * however, messages must only be distributed to current channel - * slaves, so the master must still acknowledge that the slave - * joined before transient messages are delivered. As approval is - * guaranteed, the presistent channel state can be synchronized freely - * immediately, prior to master confirmation. - */ - GNUNET_PSYC_CHANNEL_OPEN - = GNUNET_PSYC_CHANNEL_RESTRICTED_HISTORY, - - /** - * The master must approve joins to the channel, but past messages can be - * freely distributed to slaves. - */ - GNUNET_PSYC_CHANNEL_CLOSED - = GNUNET_PSYC_CHANNEL_ADMISSION_CONTROL, -#endif -}; - - -enum GNUNET_PSYC_MessageFlags -{ - /** - * Default / no flags. - */ - GNUNET_PSYC_MESSAGE_DEFAULT = 0, - - /** - * Historic message, retrieved from PSYCstore. - */ - GNUNET_PSYC_MESSAGE_HISTORIC = 1 << 0, - - /** - * Request from slave to master. - */ - GNUNET_PSYC_MESSAGE_REQUEST = 1 << 1, - - /** - * Message can be delivered out of order. - */ - GNUNET_PSYC_MESSAGE_ORDER_ANY = 1 << 2 -}; - - -/** - * Values for the @a state_delta field of GNUNET_PSYC_MessageHeader. - */ -enum GNUNET_PSYC_StateDeltaValues -{ - GNUNET_PSYC_STATE_RESET = 0, - - GNUNET_PSYC_STATE_NOT_MODIFIED = UINT64_MAX -}; - - -GNUNET_NETWORK_STRUCT_BEGIN - -/** - * A PSYC message. - * - * Used for single-fragment messages e.g. in a join request or response. - */ -struct GNUNET_PSYC_Message -{ - /** - * Message header with size and type information. - */ - struct GNUNET_MessageHeader header; - - /* Followed by concatenated PSYC message parts: - * messages with GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_* types - */ -}; - - -/** - * Header of a PSYC message. - * - * The PSYC service adds this when delivering the message to local clients, - * not present on the multicast layer. - */ -struct GNUNET_PSYC_MessageHeader -{ - /** - * Generic message header with size and type information. - */ - struct GNUNET_MessageHeader header; - - /** - * Flags for this message fragment. - * - * @see enum GNUNET_PSYC_MessageFlags - */ - uint32_t flags GNUNET_PACKED; - - /** - * Number of the message this message part belongs to. - * Monotonically increasing from 1. - */ - uint64_t message_id GNUNET_PACKED; - - /** - * Byte offset of this @e fragment of the @e message. - */ - uint64_t fragment_offset GNUNET_PACKED; - - /** - * Sending slave's public key. - * Not set if the message is from the master. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; - - /* Followed by concatenated PSYC message parts: - * messages with GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_* types - */ -}; - - -/** - * The method of a message. - */ -struct GNUNET_PSYC_MessageMethod -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD - */ - struct GNUNET_MessageHeader header; - - /** - * OR'ed GNUNET_PSYC_MasterTransmitFlags - */ - uint32_t flags GNUNET_PACKED; - - /** - * Number of message IDs since the last message that contained state - * operations. @see enum GNUNET_PSYC_StateDeltaValues - */ - uint64_t state_delta GNUNET_PACKED; - - /* Followed by NUL-terminated method name. */ -}; - - -/** - * A modifier of a message. - */ -struct GNUNET_PSYC_MessageModifier -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER - */ - struct GNUNET_MessageHeader header; - - /** - * Size of value. - */ - uint32_t value_size GNUNET_PACKED; - - /** - * Size of name, including NUL terminator. - */ - uint16_t name_size GNUNET_PACKED; - - /** - * enum GNUNET_PSYC_Operator - */ - uint8_t oper; - - /* Followed by NUL-terminated name, then the value. */ -}; - - -struct GNUNET_PSYC_CountersResultMessage -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYC_RESULT_COUNTERS - */ - struct GNUNET_MessageHeader header; - - /** - * Status code for the operation. - */ - uint32_t result_code GNUNET_PACKED; - - /** - * Last message ID sent to the channel. - */ - uint64_t max_message_id GNUNET_PACKED; -}; - - -/** - * Join request sent to a PSYC master. - */ -struct GNUNET_PSYC_JoinRequestMessage -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYC_MASTER_JOIN_REQUEST - */ - struct GNUNET_MessageHeader header; - /** - * Public key of the joining slave. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; - - /* Followed by struct GNUNET_MessageHeader join_request */ -}; - - -/** - * Join decision sent in reply to a join request. - */ -struct GNUNET_PSYC_JoinDecisionMessage -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION - */ - struct GNUNET_MessageHeader header; - - /** - * #GNUNET_YES if the slave was admitted. - */ - int32_t is_admitted; - - /** - * Public key of the joining slave. - * Only set when the master is sending the decision, - * not set when a slave is receiving it. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; - - /* Followed by struct GNUNET_MessageHeader join_response */ -}; - - -enum GNUNET_PSYC_HistoryReplayFlags -{ - /** - * Replay locally available messages. - */ - GNUNET_PSYC_HISTORY_REPLAY_LOCAL = 0, - - /** - * Replay messages from remote peers if not found locally. - */ - GNUNET_PSYC_HISTORY_REPLAY_REMOTE = 1, -}; - - -struct GNUNET_PSYC_HistoryRequestMessage -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_HISTORY_REPLAY - */ - struct GNUNET_MessageHeader header; - - /** - * @see enum GNUNET_PSYC_HistoryReplayFlags - */ - uint32_t flags GNUNET_PACKED; - - /** - * ID for this operation. - */ - uint64_t op_id GNUNET_PACKED; - - uint64_t start_message_id GNUNET_PACKED; - - uint64_t end_message_id GNUNET_PACKED; - - uint64_t message_limit GNUNET_PACKED; - - /* Followed by NUL-terminated method name prefix. */ -}; - - -struct GNUNET_PSYC_StateRequestMessage -{ - /** - * Types: - * - GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_STATE_GET - * - GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_STATE_GET_PREFIX - */ - struct GNUNET_MessageHeader header; - - uint32_t reserved GNUNET_PACKED; - - /** - * ID for this operation. - */ - uint64_t op_id GNUNET_PACKED; - - /* Followed by NUL-terminated name. */ -}; - - -/**** service -> library ****/ - - -/** - * Answer from service to client about last operation. - */ -struct GNUNET_PSYC_OperationResultMessage -{ - /** - * Types: - * - GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE - * - GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_STATE_RESULT - */ - struct GNUNET_MessageHeader header; - - uint32_t reserved GNUNET_PACKED; - - /** - * Operation ID. - */ - uint64_t op_id GNUNET_PACKED; - - /** - * Status code for the operation. - */ - uint64_t result_code GNUNET_PACKED; - - /* Followed by: - * - on error: NUL-terminated error message - * - on success: one of the following message types - * - * For a STATE_RESULT, one of: - * - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER - * - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT - * - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END - */ -}; - -GNUNET_NETWORK_STRUCT_END - - -#define GNUNET_PSYC_MODIFIER_MAX_PAYLOAD \ - GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD \ - - sizeof (struct GNUNET_PSYC_MessageModifier) - -#define GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD \ - GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD \ - - sizeof (struct GNUNET_MessageHeader) - -#define GNUNET_PSYC_DATA_MAX_PAYLOAD \ - GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD \ - - sizeof (struct GNUNET_MessageHeader) - - -/** - * PSYC message part processing states. - */ -enum GNUNET_PSYC_MessageState -{ - GNUNET_PSYC_MESSAGE_STATE_START = 0, - GNUNET_PSYC_MESSAGE_STATE_HEADER = 1, - GNUNET_PSYC_MESSAGE_STATE_METHOD = 2, - GNUNET_PSYC_MESSAGE_STATE_MODIFIER = 3, - GNUNET_PSYC_MESSAGE_STATE_MOD_CONT = 4, - GNUNET_PSYC_MESSAGE_STATE_DATA = 5, - GNUNET_PSYC_MESSAGE_STATE_END = 6, - GNUNET_PSYC_MESSAGE_STATE_CANCEL = 7, - GNUNET_PSYC_MESSAGE_STATE_ERROR = 8, -}; - - -/** - * Handle that identifies a join request. - * - * Used to match calls to #GNUNET_PSYC_JoinCallback to the - * corresponding calls to GNUNET_PSYC_join_decision(). - */ -struct GNUNET_PSYC_JoinHandle; - - -/** - * Method called from PSYC upon receiving a message. - * - * @param cls Closure. - * @param message_id Sequence number of the message. - * @param flags OR'ed GNUNET_PSYC_MessageFlags - * @param msg Message part, one of the following types: - */ -typedef void -(*GNUNET_PSYC_MessageCallback) (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg); - - -/** - * Method called from PSYC upon receiving part of a message. - * - * @param cls - * Closure. - * @param slave_pub_key - * Public key of the slave sending the message. - * Only set for channel master. - * @param message_id - * Sequence number of the message. - * @param flags - * OR'ed GNUNET_PSYC_MessageFlags - * @param fragment_offset - * Multicast message fragment offset. - * @param msg Message part, one of the following types: - * - #GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_HEADER - * - #GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD - * - #GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER - * - #GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT - * - #GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA - * or NULL if an error occurred while receiving a message. - */ -typedef void -(*GNUNET_PSYC_MessagePartCallback) (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg); - - -/** - * Method called from PSYC upon receiving a join request. - * - * @param cls - * Closure. - * @param slave_pub_key - * Public key of the slave requesting join. - * @param join_msg - * Join message sent along with the request. - * @param jh - * Join handle to use with GNUNET_PSYC_join_decision() - */ -typedef void -(*GNUNET_PSYC_JoinRequestCallback) (void *cls, - const struct GNUNET_PSYC_JoinRequestMessage *req, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key, - const struct GNUNET_PSYC_Message *join_msg, - struct GNUNET_PSYC_JoinHandle *jh); - - -/** - * Function to call with the decision made for a join request. - * - * Must be called once and only once in response to an invocation of the - * #GNUNET_PSYC_JoinCallback. - * - * @param jh Join request handle. - * @param is_admitted - * #GNUNET_YES if the join is approved, - * #GNUNET_NO if it is disapproved, - * #GNUNET_SYSERR if we cannot answer the request. - * @param relay_count Number of relays given. - * @param relays Array of suggested peers that might be useful relays to use - * when joining the multicast group (essentially a list of peers that - * are already part of the multicast group and might thus be willing - * to help with routing). If empty, only this local peer (which must - * be the multicast origin) is a good candidate for building the - * multicast tree. Note that it is unnecessary to specify our own - * peer identity in this array. - * @param join_resp Application-dependent join response message to send along - * with the decision. - * - * @return #GNUNET_OK on success, - * #GNUNET_SYSERR if @a join_resp is too large. - */ -int -GNUNET_PSYC_join_decision (struct GNUNET_PSYC_JoinHandle *jh, - int is_admitted, - uint32_t relay_count, - const struct GNUNET_PeerIdentity *relays, - const struct GNUNET_PSYC_Message *join_resp); - - -/** - * Handle for the master of a PSYC channel. - */ -struct GNUNET_PSYC_Master; - - -/** - * Function called once we are connected to the PSYC service - * and the channel master is started. - * - * Also called when we reconnected to the service - * after the connection closed unexpectedly. - * - * @param cls - * Closure. - * @param result - * #GNUNET_YES if there were already messages sent to the channel, - * #GNUNET_NO if the message history is empty, - * #GNUNET_SYSERR on error. - * @param max_message_id - * Last message ID sent to the channel. - */ -typedef void -(*GNUNET_PSYC_MasterStartCallback) (void *cls, int result, - uint64_t max_message_id); - - -/** - * Start a PSYC master channel. - * - * Will start a multicast group identified by the given ECC key. Messages - * received from group members will be given to the respective handler methods. - * If a new member wants to join a group, the "join" method handler will be - * invoked; the join handler must then generate a "join" message to approve the - * joining of the new member. The channel can also change group membership - * without explicit requests. Note that PSYC doesn't itself "understand" join - * or part messages, the respective methods must call other PSYC functions to - * inform PSYC about the meaning of the respective events. - * - * @param cfg Configuration to use (to connect to PSYC service). - * @param channel_key ECC key that will be used to sign messages for this - * PSYC session. The public key is used to identify the PSYC channel. - * Note that end-users will usually not use the private key directly, but - * rather look it up in GNS for places managed by other users, or select - * a file with the private key(s) when setting up their own channels - * FIXME: we'll likely want to use NOT the p521 curve here, but a cheaper - * one in the future. - * @param policy Channel policy specifying join and history restrictions. - * Used to automate join decisions. - * @param master_start_cb Function to invoke after the channel master started. - * @param join_request_cb Function to invoke when a slave wants to join. - * @param message_cb Function to invoke on message parts sent to the channel - * and received from slaves - * @param cls Closure for @a method and @a join_cb. - * - * @return Handle for the channel master, NULL on error. - */ -struct GNUNET_PSYC_Master * -GNUNET_PSYC_master_start (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key, - enum GNUNET_PSYC_Policy policy, - GNUNET_PSYC_MasterStartCallback master_start_cb, - GNUNET_PSYC_JoinRequestCallback join_request_cb, - GNUNET_PSYC_MessageCallback message_cb, - GNUNET_PSYC_MessagePartCallback message_part_cb, - void *cls); - - -/** - * Function called to provide data for a transmission via PSYC. - * - * Note that returning #GNUNET_YES or #GNUNET_SYSERR (but not #GNUNET_NO) - * invalidates the respective transmission handle. - * - * @param cls Closure. - * @param[in,out] data_size Initially set to the number of bytes available in - * @a data, should be set to the number of bytes written to data. - * @param[out] data Where to write the body of the message to give to the - * method. The function must copy at most @a data_size bytes to @a data. - * @return #GNUNET_SYSERR on error (fatal, aborts transmission) - * #GNUNET_NO on success, if more data is to be transmitted later. - * Should be used if @a data_size was not big enough to take all the - * data. If 0 is returned in @a data_size the transmission is paused, - * and can be resumed with GNUNET_PSYC_master_transmit_resume(). - * #GNUNET_YES if this completes the transmission (all data supplied) - */ -typedef int -(*GNUNET_PSYC_TransmitNotifyData) (void *cls, - uint16_t *data_size, - void *data); - -/** - * Function called to provide a modifier for a transmission via PSYC. - * - * Note that returning #GNUNET_YES or #GNUNET_SYSERR (but not #GNUNET_NO) - * invalidates the respective transmission handle. - * - * @param cls Closure. - * @param[in,out] data_size Initially set to the number of bytes available in - * @a data, should be set to the number of bytes written to data. - * @param[out] data Where to write the modifier's name and value. - * The function must copy at most @a data_size bytes to @a data. - * When this callback is first called for a modifier, @a data should - * contain: "name\0value". If the whole value does not fit, subsequent - * calls to this function should write continuations of the value to - * @a data. - * @param[out] oper Where to write the operator of the modifier. - * Only needed during the first call to this callback at the beginning - * of the modifier. In case of subsequent calls asking for value - * continuations @a oper is set to #NULL. - * @param[out] full_value_size Where to write the full size of the value. - * Only needed during the first call to this callback at the beginning - * of the modifier. In case of subsequent calls asking for value - * continuations @a value_size is set to #NULL. - * @return #GNUNET_SYSERR on error (fatal, aborts transmission) - * #GNUNET_NO on success, if more data is to be transmitted later. - * Should be used if @a data_size was not big enough to take all the - * data for the modifier's value (the name must be always returned - * during the first call to this callback). - * If 0 is returned in @a data_size the transmission is paused, - * and can be resumed with GNUNET_PSYC_master_transmit_resume(). - * #GNUNET_YES if this completes the modifier (the whole value is supplied). - */ -typedef int -(*GNUNET_PSYC_TransmitNotifyModifier) (void *cls, - uint16_t *data_size, - void *data, - uint8_t *oper, - uint32_t *full_value_size); - -/** - * Flags for transmitting messages to a channel by the master. - */ -enum GNUNET_PSYC_MasterTransmitFlags -{ - GNUNET_PSYC_MASTER_TRANSMIT_NONE = 0, - - /** - * Whether this message should reset the channel state, - * i.e. remove all previously stored state variables. - */ - - GNUNET_PSYC_MASTER_TRANSMIT_STATE_RESET = 1 << 0, - - /** - * Whether this message contains any state modifiers. - */ - GNUNET_PSYC_MASTER_TRANSMIT_STATE_MODIFY = 1 << 1, - - /** - * Add PSYC header variable with the hash of the current channel state. - */ - GNUNET_PSYC_MASTER_TRANSMIT_STATE_HASH = 1 << 2, - - /** - * Whether we need to increment the group generation counter after - * transmitting this message. - */ - GNUNET_PSYC_MASTER_TRANSMIT_INC_GROUP_GEN = 1 << 3 -}; - - -/** - * Handle for a pending PSYC transmission operation. - */ -struct GNUNET_PSYC_MasterTransmitHandle; - - -/** - * Send a message to call a method to all members in the PSYC channel. - * - * @param master Handle to the PSYC channel. - * @param method_name Which method should be invoked. - * @param notify_mod Function to call to obtain modifiers. - * @param notify_data Function to call to obtain fragments of the data. - * @param notify_cls Closure for @a notify_mod and @a notify_data. - * @param flags Flags for the message being transmitted. - * @return Transmission handle, NULL on error (i.e. more than one request queued). - */ -struct GNUNET_PSYC_MasterTransmitHandle * -GNUNET_PSYC_master_transmit (struct GNUNET_PSYC_Master *master, - const char *method_name, - GNUNET_PSYC_TransmitNotifyModifier notify_mod, - GNUNET_PSYC_TransmitNotifyData notify_data, - void *notify_cls, - enum GNUNET_PSYC_MasterTransmitFlags flags); - - -/** - * Resume transmission to the channel. - * - * @param th Handle of the request that is being resumed. - */ -void -GNUNET_PSYC_master_transmit_resume (struct GNUNET_PSYC_MasterTransmitHandle *th); - - -/** - * Abort transmission request to channel. - * - * @param th Handle of the request that is being aborted. - */ -void -GNUNET_PSYC_master_transmit_cancel (struct GNUNET_PSYC_MasterTransmitHandle *th); - - -/** - * Relay a message - * - * @param master Handle to the PSYC channel. - * @param method_name Which method should be invoked. - * @param notify_mod Function to call to obtain modifiers. - * @param notify_data Function to call to obtain fragments of the data. - * @param notify_cls Closure for @a notify_mod and @a notify_data. - * @param flags Flags for the message being transmitted. - * @return Transmission handle, NULL on error (i.e. more than one request queued). - */ -struct GNUNET_PSYC_MasterTransmitHandle * -GNUNET_PSYC_master_relay (struct GNUNET_PSYC_Master *master, - uint64_t message_id); - - -/** - * Stop a PSYC master channel. - * - * @param master - * PSYC channel master to stop. - * @param keep_active - * Keep place active after last application disconnected. - * @param stop_cb - * Function called after the master stopped - * and disconnected from the psyc service. - * @param stop_cls - * Closure for @a part_cb. - */ -void -GNUNET_PSYC_master_stop (struct GNUNET_PSYC_Master *master, - int keep_active, - GNUNET_ContinuationCallback stop_cb, - void *stop_cls); - - -/** - * Handle for a PSYC channel slave. - */ -struct GNUNET_PSYC_Slave; - - -/** - * Function called after the slave connected to the PSYC service. - * - * Also called when reconnected to the service - * after the connection closed unexpectedly. - * - * @param cls - * Closure. - * @param result - * #GNUNET_YES if there were already messages sent to the channel, - * #GNUNET_NO if the message history is empty, - * #GNUNET_SYSERR on error. - * @param max_message_id - * Last message ID sent to the channel. - */ -typedef void -(*GNUNET_PSYC_SlaveConnectCallback) (void *cls, int result, - uint64_t max_message_id); - - -/** - * Method called to inform about the decision in response to a join request. - * - * If @a is_admitted is not #GNUNET_YES, then sending messages to the channel is - * not possible, but earlier history can be still queried. - * - * @param cls Closure. - * @param is_admitted #GNUNET_YES or #GNUNET_NO or #GNUNET_SYSERR - * @param join_msg Application-dependent join message from the origin. - */ -typedef void -(*GNUNET_PSYC_JoinDecisionCallback) (void *cls, - const struct GNUNET_PSYC_JoinDecisionMessage *dcsn, - int is_admitted, - const struct GNUNET_PSYC_Message *join_msg); - -/** - * Flags for GNUNET_PSYC_slave_join() - */ -enum GNUNET_PSYC_SlaveJoinFlags -{ - GNUNET_PSYC_SLAVE_JOIN_NONE = 0, - - /** - * Local join for history access, no network connection is established. - */ - GNUNET_PSYC_SLAVE_JOIN_LOCAL = 1, -}; - - -/** - * Join a PSYC channel. - * - * The entity joining is always the local peer. The user must immediately use - * the GNUNET_PSYC_slave_transmit() functions to transmit a @e join_msg to the - * channel; if the join request succeeds, the channel state (and @e recent - * method calls) will be replayed to the joining member. There is no explicit - * notification on failure (as the channel may simply take days to approve, - * and disapproval is simply being ignored). - * - * @param cfg - * Configuration to use. - * @param channel_pub_key - * ECC public key that identifies the channel we wish to join. - * @param slave_pub_key - * ECC private-public key pair that identifies the slave, and - * used by multicast to sign the join request and subsequent unicast - * requests sent to the master. - * @param flags - * Join flags. - * @param origin - * Peer identity of the origin. - * @param relay_count - * Number of peers in the @a relays array. - * @param relays - * Peer identities of members of the multicast group, which serve - * as relays and used to join the group at. - * @param message_cb - * Function to invoke on message fragments received from the channel. - * @param message_part_cb - * Function to invoke on message parts received from the channel. - * @param slave_connect_cb - * Function invoked once we have connected to the PSYC service. - * @param join_decision_cb - * Function invoked once we have received a join decision. - * @param cls - * Closure for @a message_cb and @a slave_joined_cb. - * @param join_msg - * Join message. - * - * @return Handle for the slave, NULL on error. - */ -struct GNUNET_PSYC_Slave * -GNUNET_PSYC_slave_join (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_pub_key, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_pub_key, - enum GNUNET_PSYC_SlaveJoinFlags flags, - const struct GNUNET_PeerIdentity *origin, - uint32_t relay_count, - const struct GNUNET_PeerIdentity *relays, - GNUNET_PSYC_MessageCallback message_cb, - GNUNET_PSYC_MessagePartCallback message_part_cb, - GNUNET_PSYC_SlaveConnectCallback slave_connect_cb, - GNUNET_PSYC_JoinDecisionCallback join_decision_cb, - void *cls, - const struct GNUNET_PSYC_Message *join_msg); - - -/** - * Part a PSYC channel. - * - * Will terminate the connection to the PSYC service. Polite clients should - * first explicitly send a part request (via GNUNET_PSYC_slave_transmit()). - * - * @param slave - * Slave handle. - * @param keep_active - * Keep place active after last application disconnected. - * @param part_cb - * Function called after the slave parted the channel - * and disconnected from the psyc service. - * @param part_cls - * Closure for @a part_cb. - */ -void -GNUNET_PSYC_slave_part (struct GNUNET_PSYC_Slave *slave, - int keep_active, - GNUNET_ContinuationCallback part_cb, - void *part_cls); - - -/** - * Flags for transmitting messages to the channel master by a slave. - */ -enum GNUNET_PSYC_SlaveTransmitFlags -{ - GNUNET_PSYC_SLAVE_TRANSMIT_NONE = 0 -}; - - -/** - * Handle for a pending PSYC transmission operation. - */ -struct GNUNET_PSYC_SlaveTransmitHandle; - - -/** - * Request a message to be sent to the channel master. - * - * @param slave Slave handle. - * @param method_name Which (PSYC) method should be invoked (on host). - * @param notify_mod Function to call to obtain modifiers. - * @param notify_data Function to call to obtain fragments of the data. - * @param notify_cls Closure for @a notify. - * @param flags Flags for the message being transmitted. - * @return Transmission handle, NULL on error (i.e. more than one request queued). - */ -struct GNUNET_PSYC_SlaveTransmitHandle * -GNUNET_PSYC_slave_transmit (struct GNUNET_PSYC_Slave *slave, - const char *method_name, - GNUNET_PSYC_TransmitNotifyModifier notify_mod, - GNUNET_PSYC_TransmitNotifyData notify_data, - void *notify_cls, - enum GNUNET_PSYC_SlaveTransmitFlags flags); - - -/** - * Resume transmission to the master. - * - * @param th Handle of the request that is being resumed. - */ -void -GNUNET_PSYC_slave_transmit_resume (struct GNUNET_PSYC_SlaveTransmitHandle *th); - - -/** - * Abort transmission request to master. - * - * @param th Handle of the request that is being aborted. - */ -void -GNUNET_PSYC_slave_transmit_cancel (struct GNUNET_PSYC_SlaveTransmitHandle *th); - - -/** - * Handle to access PSYC channel operations for both the master and slaves. - */ -struct GNUNET_PSYC_Channel; - - -/** - * Convert a channel @a master to a @e channel handle to access the @e channel - * APIs. - * - * @param master Channel master handle. - * @return Channel handle, valid for as long as @a master is valid. - */ -struct GNUNET_PSYC_Channel * -GNUNET_PSYC_master_get_channel (struct GNUNET_PSYC_Master *master); - - -/** - * Convert @a slave to a @e channel handle to access the @e channel APIs. - * - * @param slave Slave handle. - * @return Channel handle, valid for as long as @a slave is valid. - */ -struct GNUNET_PSYC_Channel * -GNUNET_PSYC_slave_get_channel (struct GNUNET_PSYC_Slave *slave); - - -/** - * Add a slave to the channel's membership list. - * - * Note that this will NOT generate any PSYC traffic, it will merely update the - * local database to modify how we react to membership test queries. - * The channel master still needs to explicitly transmit a @e join message to - * notify other channel members and they then also must still call this function - * in their respective methods handling the @e join message. This way, how @e - * join and @e part operations are exactly implemented is still up to the - * application; for example, there might be a @e part_all method to kick out - * everyone. - * - * Note that channel slaves are explicitly trusted to execute such methods - * correctly; not doing so correctly will result in either denying other slaves - * access or offering access to channel data to non-members. - * - * @param channel - * Channel handle. - * @param slave_pub_key - * Identity of channel slave to add. - * @param announced_at - * ID of the message that announced the membership change. - * @param effective_since - * Addition of slave is in effect since this message ID. - * @param result_cb - * Function to call with the result of the operation. - * The @e result_code argument is #GNUNET_OK on success, or - * #GNUNET_SYSERR on error. In case of an error, the @e data argument - * can contain an optional error message. - * @param cls - * Closure for @a result_cb. - */ -void -GNUNET_PSYC_channel_slave_add (struct GNUNET_PSYC_Channel *channel, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key, - uint64_t announced_at, - uint64_t effective_since, - GNUNET_ResultCallback result_cb, - void *cls); - - -/** - * Remove a slave from the channel's membership list. - * - * Note that this will NOT generate any PSYC traffic, it will merely update the - * local database to modify how we react to membership test queries. - * The channel master still needs to explicitly transmit a @e part message to - * notify other channel members and they then also must still call this function - * in their respective methods handling the @e part message. This way, how - * @e join and @e part operations are exactly implemented is still up to the - * application; for example, there might be a @e part_all message to kick out - * everyone. - * - * Note that channel members are explicitly trusted to perform these - * operations correctly; not doing so correctly will result in either - * denying members access or offering access to channel data to - * non-members. - * - * @param channel - * Channel handle. - * @param slave_pub_key - * Identity of channel slave to remove. - * @param announced_at - * ID of the message that announced the membership change. - * @param result_cb - * Function to call with the result of the operation. - * The @e result_code argument is #GNUNET_OK on success, or - * #GNUNET_SYSERR on error. In case of an error, the @e data argument - * can contain an optional error message. - * @param cls - * Closure for @a result_cb. - */ -void -GNUNET_PSYC_channel_slave_remove (struct GNUNET_PSYC_Channel *channel, - const struct GNUNET_CRYPTO_EcdsaPublicKey - *slave_pub_key, - uint64_t announced_at, - GNUNET_ResultCallback result_cb, - void *cls); - - -/** - * History request handle. - */ -struct GNUNET_PSYC_HistoryRequest; - - -/** - * Request to replay a part of the message history of the channel. - * - * Historic messages (but NOT the state at the time) will be replayed (given to - * the normal method handlers) if available and if access is permitted. - * - * @param channel - * Which channel should be replayed? - * @param start_message_id - * Earliest interesting point in history. - * @param end_message_id - * Last (inclusive) interesting point in history. - * @param method_prefix - * Retrieve only messages with a matching method prefix. - * @param flags - * OR'ed enum GNUNET_PSYC_HistoryReplayFlags - * @param result_cb - * Function to call when the requested history has been fully replayed. - * Once this function has been called, the client must not call - * GNUNET_PSYC_channel_history_replay_cancel() anymore. - * @param cls - * Closure for the callbacks. - * - * @return Handle to cancel history replay operation. - */ -struct GNUNET_PSYC_HistoryRequest * -GNUNET_PSYC_channel_history_replay (struct GNUNET_PSYC_Channel *channel, - uint64_t start_message_id, - uint64_t end_message_id, - const char *method_prefix, - uint32_t flags, - GNUNET_PSYC_MessageCallback message_cb, - GNUNET_PSYC_MessagePartCallback message_part_cb, - GNUNET_ResultCallback result_cb, - void *cls); - - -/** - * Request to replay the latest messages from the message history of the channel. - * - * Historic messages (but NOT the state at the time) will be replayed (given to - * the normal method handlers) if available and if access is permitted. - * - * @param channel - * Which channel should be replayed? - * @param message_limit - * Maximum number of messages to replay. - * @param flags - * OR'ed enum GNUNET_PSYC_HistoryReplayFlags - * @param finish_cb - * Function to call when the requested history has been fully replayed - * (counting message IDs might not suffice, as some messages might be - * secret and thus the listener would not know the story is finished - * without being told explicitly)o once this function has been called, the - * client must not call GNUNET_PSYC_channel_history_replay_cancel() anymore. - * @param cls - * Closure for the callbacks. - * - * @return Handle to cancel history replay operation. - */ -struct GNUNET_PSYC_HistoryRequest * -GNUNET_PSYC_channel_history_replay_latest (struct GNUNET_PSYC_Channel *channel, - uint64_t message_limit, - const char *method_prefix, - uint32_t flags, - GNUNET_PSYC_MessageCallback message_cb, - GNUNET_PSYC_MessagePartCallback message_part_cb, - GNUNET_ResultCallback result_cb, - void *cls); - - -void -GNUNET_PSYC_channel_history_replay_cancel (struct GNUNET_PSYC_Channel *channel, - struct GNUNET_PSYC_HistoryRequest *hr); - - -/** - * Function called to inform a member about stored state values for a channel. - * - * If @a full_value_size > value_size then this function is called multiple - * times until the whole value arrived. - * - * @param cls - * Closure. - * @param name - * Name of the state variable. - * NULL if there are no more state variables to be returned. - * @param value - * Value of the state variable. - * @param value_size - * Number of bytes in @a value. - * @param full_value_size - * Number of bytes in the full value, including continuations. - * Only set for the first part of a variable, - * in case of a continuation it is 0. - */ -typedef void -(*GNUNET_PSYC_StateVarCallback) (void *cls, - const struct GNUNET_MessageHeader *mod, - const char *name, - const void *value, - uint32_t value_size, - uint32_t full_value_size); - - -/** - * State request handle. - */ -struct GNUNET_PSYC_StateRequest; - - -/** - * Retrieve the best matching channel state variable. - * - * If the requested variable name is not present in the state, the nearest - * less-specific name is matched; for example, requesting "_a_b" will match "_a" - * if "_a_b" does not exist. - * - * @param channel - * Channel handle. - * @param full_name - * Full name of the requested variable. - * The actual variable returned might have a shorter name. - * @param var_cb - * Function called once when a matching state variable is found. - * Not called if there's no matching state variable. - * @param result_cb - * Function called after the operation finished. - * (i.e. all state variables have been returned via @a state_cb) - * @param cls - * Closure for the callbacks. - */ -struct GNUNET_PSYC_StateRequest * -GNUNET_PSYC_channel_state_get (struct GNUNET_PSYC_Channel *channel, - const char *full_name, - GNUNET_PSYC_StateVarCallback var_cb, - GNUNET_ResultCallback result_cb, - void *cls); - - -/** - * Return all channel state variables whose name matches a given prefix. - * - * A name matches if it starts with the given @a name_prefix, thus requesting - * the empty prefix ("") will match all values; requesting "_a_b" will also - * return values stored under "_a_b_c". - * - * The @a state_cb is invoked on all matching state variables asynchronously, as - * the state is stored in and retrieved from the PSYCstore, - * - * @param channel - * Channel handle. - * @param name_prefix - * Prefix of the state variable name to match. - * @param var_cb - * Function called once when a matching state variable is found. - * Not called if there's no matching state variable. - * @param result_cb - * Function called after the operation finished. - * (i.e. all state variables have been returned via @a state_cb) - * @param cls - * Closure for the callbacks. - */ -struct GNUNET_PSYC_StateRequest * -GNUNET_PSYC_channel_state_get_prefix (struct GNUNET_PSYC_Channel *channel, - const char *name_prefix, - GNUNET_PSYC_StateVarCallback var_cb, - GNUNET_ResultCallback result_cb, - void *cls); - -/** - * Cancel a state request operation. - * - * @param sr - * Handle for the operation to cancel. - */ -void -GNUNET_PSYC_channel_state_get_cancel (struct GNUNET_PSYC_StateRequest *sr); - - - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef GNUNET_PSYC_SERVICE_H */ -#endif - -/** @} */ /* end of group */ diff --git a/src/include/gnunet_psyc_slicer.h b/src/include/gnunet_psyc_slicer.h deleted file mode 100644 index 87f66d7e8..000000000 --- a/src/include/gnunet_psyc_slicer.h +++ /dev/null @@ -1,378 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2013 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later -*/ - -/** - * @author Gabor X Toth - * @author Christian Grothoff - * - * @file - * PSYC Slicer library - * - * @defgroup psyc-util-slicer PSYC Utilities library: Slicer - * Try-and-slice processing of PSYC method names and environment. - * @{ - */ - -#ifndef GNUNET_PSYC_SLICER_H -#define GNUNET_PSYC_SLICER_H - - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "gnunet_util_lib.h" - - -/** - * Handle to an implementation of try-and-slice. - */ -struct GNUNET_PSYC_Slicer; - - -/** - * Function called upon receiving a message indicating a call to a @e method. - * - * This function is called one or more times for each message until all data - * fragments arrive from the network. - * - * @param cls - * Closure. - * @param msg - * Message part, as it arrived from the network. - * @param message_id - * Message counter, monotonically increasing from 1. - * @param flags - * OR'ed GNUNET_PSYC_MessageFlags - * @param fragment_offset - * Multicast message fragment offset. - * @param tmit_flags - * OR'ed GNUNET_PSYC_MasterTransmitFlags - * @param nym - * The sender of the message. - * Can be NULL if the message is not connected to a pseudonym. - * @param method_name - * Original method name from PSYC. - * May be more specific than the registered method name due to - * try-and-slice matching. - */ -typedef void -(*GNUNET_PSYC_MethodCallback) (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_PSYC_MessageMethod *meth, - uint64_t message_id, - const char *method_name); - - -/** - * Function called upon receiving a modifier of a message. - * - * @param cls - * Closure. - * @param message_id - * Message ID this data fragment belongs to. - * @param flags - * OR'ed GNUNET_PSYC_MessageFlags - * @param fragment_offset - * Multicast message fragment offset. - * @param msg - * Message part, as it arrived from the network. - * @param oper - * Operation to perform. - * 0 in case of a modifier continuation. - * @param name - * Name of the modifier. - * NULL in case of a modifier continuation. - * @param value - * Value of the modifier. - * @param value_size - * Size of @value. - */ -typedef void -(*GNUNET_PSYC_ModifierCallback) (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg, - uint64_t message_id, - enum GNUNET_PSYC_Operator oper, - const char *name, - const void *value, - uint16_t value_size, - uint16_t full_value_size); - - -/** - * Function called upon receiving a data fragment of a message. - * - * @param cls - * Closure. - * @param msg - * Message part, as it arrived from the network. - * @param message_id - * Message ID this data fragment belongs to. - * @param flags - * OR'ed GNUNET_PSYC_MessageFlags - * @param fragment_offset - * Multicast message fragment offset. - * @param data - * Data stream given to the method. - * @param data_size - * Number of bytes in @a data. - * @param end - * End of message? - * #GNUNET_NO if there are further fragments, - * #GNUNET_YES if this is the last fragment, - * #GNUNET_SYSERR indicates the message was cancelled by the sender. - */ -typedef void -(*GNUNET_PSYC_DataCallback) (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg, - uint64_t message_id, - const void *data, - uint16_t data_size); - - -/** - * End of message. - * - * @param cls - * Closure. - * @param msg - * Message part, as it arrived from the network. - * @param message_id - * Message ID this data fragment belongs to. - * @param flags - * OR'ed GNUNET_PSYC_MessageFlags - * @param fragment_offset - * Multicast message fragment offset. - * @param cancelled - * #GNUNET_YES if the message was cancelled, - * #GNUNET_NO if the message is complete. - */ -typedef void -(*GNUNET_PSYC_EndOfMessageCallback) (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg, - uint64_t message_id, - uint8_t is_cancelled); - - -/** - * Create a try-and-slice instance. - * - * A slicer processes incoming messages and notifies callbacks about matching - * methods or modifiers encountered. - * - * @return A new try-and-slice construct. - */ -struct GNUNET_PSYC_Slicer * -GNUNET_PSYC_slicer_create (void); - - -/** - * Add a method to the try-and-slice instance. - * - * The callbacks are called for messages with a matching @a method_name prefix. - * - * @param slicer - * The try-and-slice instance to extend. - * @param method_name - * Name of the given method, use empty string to match all. - * @param method_cb - * Method handler invoked upon a matching message. - * @param modifier_cb - * Modifier handler, invoked after @a method_cb - * for each modifier in the message. - * @param data_cb - * Data handler, invoked after @a modifier_cb for each data fragment. - * @param eom_cb - * Invoked upon reaching the end of a matching message. - * @param cls - * Closure for the callbacks. - */ -void -GNUNET_PSYC_slicer_method_add (struct GNUNET_PSYC_Slicer *slicer, - const char *method_name, - GNUNET_PSYC_MessageCallback msg_cb, - GNUNET_PSYC_MethodCallback method_cb, - GNUNET_PSYC_ModifierCallback modifier_cb, - GNUNET_PSYC_DataCallback data_cb, - GNUNET_PSYC_EndOfMessageCallback eom_cb, - void *cls); - -/** - * Remove a registered method from the try-and-slice instance. - * - * Removes one matching handler registered with the given - * @a method_name and callbacks. - * - * @param slicer - * The try-and-slice instance. - * @param method_name - * Name of the method to remove. - * @param method_cb - * Only remove matching method handler, or NULL. - * @param modifier_cb - * Only remove matching modifier handler, or NULL. - * @param data_cb - * Only remove matching data handler, or NULL. - * @param eom_cb - * Only remove matching End of Message handler, or NULL. - * - * @return #GNUNET_OK if a method handler was removed, - * #GNUNET_NO if no handler matched the given method name and callbacks. - */ -int -GNUNET_PSYC_slicer_method_remove (struct GNUNET_PSYC_Slicer *slicer, - const char *method_name, - GNUNET_PSYC_MessageCallback msg_cb, - GNUNET_PSYC_MethodCallback method_cb, - GNUNET_PSYC_ModifierCallback modifier_cb, - GNUNET_PSYC_DataCallback data_cb, - GNUNET_PSYC_EndOfMessageCallback eom_cb); - - -/** - * Watch a place for changed objects. - * - * @param slicer - * The try-and-slice instance. - * @param object_filter - * Object prefix to match. - * @param modifier_cb - * Function to call when encountering a state modifier. - * @param cls - * Closure for callback. - */ -void -GNUNET_PSYC_slicer_modifier_add (struct GNUNET_PSYC_Slicer *slicer, - const char *object_filter, - GNUNET_PSYC_ModifierCallback modifier_cb, - void *cls); - - -/** - * Remove a registered modifier from the try-and-slice instance. - * - * Removes one matching handler registered with the given - * @a object_filter and callback. - * - * @param slicer - * The try-and-slice instance. - * @param object_filter - * Object prefix to match. - * @param modifier_cb - * Function to call when encountering a state modifier changes. - */ -int -GNUNET_PSYC_slicer_modifier_remove (struct GNUNET_PSYC_Slicer *slicer, - const char *object_filter, - GNUNET_PSYC_ModifierCallback modifier_cb); - - -/** - * Process an incoming message and call matching handlers. - * - * @param slicer - * The slicer to use. - * @param msg - * The message as it arrived from the network. - */ -void -GNUNET_PSYC_slicer_message (struct GNUNET_PSYC_Slicer *slicer, - const struct GNUNET_PSYC_MessageHeader *msg); - - -/** - * Process an incoming message part and call matching handlers. - * - * @param slicer - * The slicer to use. - * @param message_id - * ID of the message. - * @param flags - * Flags for the message. - * @see enum GNUNET_PSYC_MessageFlags - * @param fragment offset - * Fragment offset of the message. - * @param msg - * The message part as it arrived from the network. - */ -void -GNUNET_PSYC_slicer_message_part (struct GNUNET_PSYC_Slicer *slicer, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg); - - -/** - * Remove all registered method handlers. - * - * @param slicer - * Slicer to clear. - */ -void -GNUNET_PSYC_slicer_method_clear (struct GNUNET_PSYC_Slicer *slicer); - - -/** - * Remove all registered modifier handlers. - * - * @param slicer - * Slicer to clear. - */ -void -GNUNET_PSYC_slicer_modifier_clear (struct GNUNET_PSYC_Slicer *slicer); - - -/** - * Remove all registered method & modifier handlers. - * - * @param slicer - * Slicer to clear. - */ -void -GNUNET_PSYC_slicer_clear (struct GNUNET_PSYC_Slicer *slicer); - - -/** - * Destroy a given try-and-slice instance. - * - * @param slicer - * Slicer to destroy - */ -void -GNUNET_PSYC_slicer_destroy (struct GNUNET_PSYC_Slicer *slicer); - - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef GNUNET_PSYC_SLICER_H */ -#endif - -/** @} */ /* end of group */ diff --git a/src/include/gnunet_psyc_util_lib.h b/src/include/gnunet_psyc_util_lib.h deleted file mode 100644 index 57eec65c3..000000000 --- a/src/include/gnunet_psyc_util_lib.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012, 2013 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later -*/ - -/** - * @author Gabor X Toth - * - * @file - * PSYC utilities: messages, environment, slicer - */ - -#ifndef GNUNET_PSYC_UTIL_LIB_H -#define GNUNET_PSYC_UTIL_LIB_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - - -#include "gnunet_psyc_env.h" -#include "gnunet_psyc_message.h" -#include "gnunet_psyc_slicer.h" - - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef GNUNET_PSYC_UTIL_LIB_H */ -#endif diff --git a/src/include/gnunet_psycstore_plugin.h b/src/include/gnunet_psycstore_plugin.h deleted file mode 100644 index fac549f43..000000000 --- a/src/include/gnunet_psycstore_plugin.h +++ /dev/null @@ -1,383 +0,0 @@ -/* - This file is part of GNUnet - Copyright (C) 2013 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later -*/ - -/** - * @author Gabor X Toth - * - * @file - * Plugin API for the PSYCstore database backend - * - * @defgroup psycstore-plugin PSYC Store plugin API - * Plugin API for the PSYC Store database backend - * @{ - */ -#ifndef GNUNET_PSYCSTORE_PLUGIN_H -#define GNUNET_PSYCSTORE_PLUGIN_H - -#include "gnunet_util_lib.h" -#include "gnunet_psycstore_service.h" - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - - -/** - * Struct returned by the initialization function of the plugin. - */ -struct GNUNET_PSYCSTORE_PluginFunctions -{ - - /** - * Closure to pass to all plugin functions. - */ - void *cls; - - /** - * Store join/leave events for a PSYC channel in order to be able to answer - * membership test queries later. - * - * @see GNUNET_PSYCSTORE_membership_store() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int - (*membership_store) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - int did_join, - uint64_t announced_at, - uint64_t effective_since, - uint64_t group_generation); - - /** - * Test if a member was admitted to the channel at the given message ID. - * - * @see GNUNET_PSYCSTORE_membership_test() - * - * @return #GNUNET_YES if the member was admitted, #GNUNET_NO if not, - * #GNUNET_SYSERR if there was en error. - */ - int - (*membership_test) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - uint64_t message_id); - - /** - * Store a message fragment sent to a channel. - * - * @see GNUNET_PSYCSTORE_fragment_store() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int - (*fragment_store) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_MULTICAST_MessageHeader *message, - uint32_t psycstore_flags); - - /** - * Set additional flags for a given message. - * - * They are OR'd with any existing flags set. - * - * @param cls Closure. - * @param channel_key Public key of the channel. - * @param message_id ID of the message. - * @param psycstore_flags OR'd GNUNET_PSYCSTORE_MessageFlags. - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int - (*message_add_flags) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id, - uint32_t psycstore_flags); - - /** - * Retrieve a message fragment range by fragment ID. - * - * @see GNUNET_PSYCSTORE_fragment_get() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int - (*fragment_get) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t first_fragment_id, - uint64_t last_fragment_id, - uint64_t *returned_fragments, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls); - - /** - * Retrieve latest message fragments. - * - * @see GNUNET_PSYCSTORE_fragment_get() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int - (*fragment_get_latest) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t fragment_limit, - uint64_t *returned_fragments, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls); - - /** - * Retrieve all fragments of a message ID range. - * - * @see GNUNET_PSYCSTORE_message_get() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int - (*message_get) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t first_fragment_id, - uint64_t last_fragment_id, - uint64_t fragment_limit, - uint64_t *returned_fragments, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls); - - /** - * Retrieve all fragments of the latest messages. - * - * @see GNUNET_PSYCSTORE_message_get() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int - (*message_get_latest) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t fragment_limit, - uint64_t *returned_fragments, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls); - - /** - * Retrieve a fragment of message specified by its message ID and fragment - * offset. - * - * @see GNUNET_PSYCSTORE_message_get_fragment() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int - (*message_get_fragment) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id, - uint64_t fragment_offset, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls); - - /** - * Retrieve the max. values of message counters for a channel. - * - * @see GNUNET_PSYCSTORE_counters_get() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int - (*counters_message_get) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t *max_fragment_id, - uint64_t *max_message_id, - uint64_t *max_group_generation); - - /** - * Retrieve the max. values of state counters for a channel. - * - * @see GNUNET_PSYCSTORE_counters_get() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int - (*counters_state_get) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t *max_state_message_id); - - - /** - * Begin modifying current state. - * - * @see GNUNET_PSYCSTORE_state_modify() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int - (*state_modify_begin) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id, uint64_t state_delta); - - /** - * Set the current value of a state variable. - * - * The state modification process is started with state_modify_begin(), - * which is followed by one or more calls to this function, - * and finished with state_modify_end(). - * - * @see GNUNET_PSYCSTORE_state_modify() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int - (*state_modify_op) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - enum GNUNET_PSYC_Operator op, - const char *name, const void *value, size_t value_size); - - - /** - * End modifying current state. - * - * @see GNUNET_PSYCSTORE_state_modify() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int - (*state_modify_end) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id); - - - /** - * Begin synchronizing state. - * - * @see GNUNET_PSYCSTORE_state_sync() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int - (*state_sync_begin) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key); - - /** - * Assign value of a state variable while synchronizing state. - * - * The state synchronization process is started with state_sync_begin(), - * which is followed by one or more calls to this function, - * and finished using state_sync_end(). - * - * @see GNUNET_PSYCSTORE_state_sync() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int - (*state_sync_assign) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const char *name, const void *value, size_t value_size); - - - /** - * End synchronizing state. - * - * @see GNUNET_PSYCSTORE_state_sync() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int - (*state_sync_end) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t max_state_message_id, - uint64_t state_hash_message_id); - - - /** - * Reset the state of a channel. - * - * Delete all state variables stored for the given channel. - * - * @see GNUNET_PSYCSTORE_state_reset() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int - (*state_reset) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key); - - /** - * Update signed state values from the current ones. - * - * Sets value_signed = value_current for each variable for the given channel. - */ - int - (*state_update_signed) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key); - - - /** - * Retrieve a state variable by name (exact match). - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int - (*state_get) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const char *name, - GNUNET_PSYCSTORE_StateCallback cb, - void *cb_cls); - - /** - * Retrieve all state variables for a channel with the given prefix. - * - * @see GNUNET_PSYCSTORE_state_get_prefix() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int - (*state_get_prefix) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const char *name, - GNUNET_PSYCSTORE_StateCallback cb, - void *cb_cls); - - - /** - * Retrieve all signed state variables for a channel. - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int - (*state_get_signed) (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - GNUNET_PSYCSTORE_StateCallback cb, - void *cb_cls); - -}; - - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -#endif - -/** @} */ /* end of group */ diff --git a/src/include/gnunet_psycstore_service.h b/src/include/gnunet_psycstore_service.h deleted file mode 100644 index 92516f447..000000000 --- a/src/include/gnunet_psycstore_service.h +++ /dev/null @@ -1,701 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2013 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later -*/ - -/** - * @author Gabor X Toth - * @author Christian Grothoff - * - * @file - * PSYCstore service; implements persistent storage for the PSYC service - * - * @defgroup psycstore PSYC Store service - * Persistent storage for the PSYC service. - * @{ - */ -#ifndef GNUNET_PSYCSTORE_SERVICE_H -#define GNUNET_PSYCSTORE_SERVICE_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "gnunet_util_lib.h" -#include "gnunet_psyc_util_lib.h" -#include "gnunet_multicast_service.h" -#include "gnunet_psyc_service.h" - -/** - * Version number of GNUnet PSYCstore API. - */ -#define GNUNET_PSYCSTORE_VERSION 0x00000000 - -/** - * Membership test failed. - */ -#define GNUNET_PSYCSTORE_MEMBERSHIP_TEST_FAILED -2 - -/** - * Flags for stored messages. - */ -enum GNUNET_PSYCSTORE_MessageFlags -{ - /** - * The message contains state modifiers. - */ - GNUNET_PSYCSTORE_MESSAGE_STATE = 1 << 0, - - /** - * The state modifiers have been applied to the state store. - */ - GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED = 1 << 1, - - /** - * The message contains a state hash. - */ - GNUNET_PSYCSTORE_MESSAGE_STATE_HASH = 1 << 2 -}; - - -/** - * Handle for a PSYCstore - */ -struct GNUNET_PSYCSTORE_Handle; - - -/** - * Connect to the PSYCstore service. - * - * @param cfg Configuration to use. - * - * @return Handle for the connecton. - */ -struct GNUNET_PSYCSTORE_Handle * -GNUNET_PSYCSTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); - - -/** - * Disconnect from the PSYCstore service. - * - * @param h Handle for the connection. - */ -void -GNUNET_PSYCSTORE_disconnect (struct GNUNET_PSYCSTORE_Handle *h); - - -/** - * Handle for an operation on the PSYCSTORE (useful to cancel the operation). - */ -struct GNUNET_PSYCSTORE_OperationHandle; - - -/** - * Function called with the result of an asynchronous operation. - * - * @param cls - * Closure. - * @param result - * Result of the operation. - * @param err_msg - * Error message, or NULL if there's no error. - * @param err_msg_size - * Size of @a err_msg - */ -typedef void -(*GNUNET_PSYCSTORE_ResultCallback) (void *cls, - int64_t result, - const char *err_msg, - uint16_t err_msg_size); - - -/** - * Store join/leave events for a PSYC channel in order to be able to answer - * membership test queries later. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel where the event happened. - * @param slave_key - * Public key of joining/leaving slave. - * @param did_join - * #GNUNET_YES on join, #GNUNET_NO on part. - * @param announced_at - * ID of the message that announced the membership change. - * @param effective_since - * Message ID this membership change is in effect since. - * For joins it is <= announced_at, for parts it is always 0. - * @param group_generation - * In case of a part, the last group generation the slave has access to. - * It has relevance when a larger message have fragments with different - * group generations. - * @param result_cb - * Callback to call with the result of the storage operation. - * @param cls - * Closure for the callback. - * - * @return Operation handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_membership_store (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - int did_join, - uint64_t announced_at, - uint64_t effective_since, - uint64_t group_generation, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls); - - -/** - * Test if a member was admitted to the channel at the given message ID. - * - * This is useful when relaying and replaying messages to check if a particular - * slave has access to the message fragment with a given group generation. It - * is also used when handling join requests to determine whether the slave is - * currently admitted to the channel. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param slave_key - * Public key of slave whose membership to check. - * @param message_id - * Message ID for which to do the membership test. - * @param group_generation - * Group generation of the fragment of the message to test. - * It has relevance if the message consists of multiple fragments with - * different group generations. - * @param result_cb - * Callback to call with the test result. - * @param cls - * Closure for the callback. - * - * @return Operation handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_membership_test (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - uint64_t message_id, - uint64_t group_generation, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls); - - -/** - * Store a message fragment sent to a channel. - * - * @param h Handle for the PSYCstore. - * @param channel_key The channel the message belongs to. - * @param msg Message to store. - * @param psycstore_flags Flags indicating whether the PSYC message contains - * state modifiers. - * @param result_cb Callback to call with the result of the operation. - * @param cls Closure for the callback. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_fragment_store (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_MULTICAST_MessageHeader *msg, - enum GNUNET_PSYCSTORE_MessageFlags psycstore_flags, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls); - - -/** - * Function called with one message fragment, as the result of a - * GNUNET_PSYCSTORE_fragment_get() or GNUNET_PSYCSTORE_message_get() call. - * - * @param cls Closure. - * @param message The retrieved message fragment. A NULL value indicates that - * there are no more results to be returned. - * @param psycstore_flags Flags stored with the message. - * - * @return #GNUNET_NO to stop calling this callback with further fragments, - * #GNUNET_YES to continue. - */ -typedef int -(*GNUNET_PSYCSTORE_FragmentCallback) (void *cls, - struct GNUNET_MULTICAST_MessageHeader *message, - enum GNUNET_PSYCSTORE_MessageFlags psycstore_flags); - - -/** - * Retrieve message fragments by fragment ID range. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param slave_key - * The slave requesting the fragment. If not NULL, a membership test is - * performed first and the fragment is only returned if the slave has - * access to it. - * @param first_fragment_id - * First fragment ID to retrieve. - * Use 0 to get the latest message fragment. - * @param last_fragment_id - * Last consecutive fragment ID to retrieve. - * Use 0 to get the latest message fragment. - * @param fragment_cb - * Callback to call with the retrieved fragments. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for the callbacks. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_fragment_get (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - uint64_t first_message_id, - uint64_t last_message_id, - GNUNET_PSYCSTORE_FragmentCallback fragment_cb, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls); - - -/** - * Retrieve latest message fragments. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param slave_key - * The slave requesting the fragment. If not NULL, a membership test is - * performed first and the fragment is only returned if the slave has - * access to it. - * @param first_fragment_id - * First fragment ID to retrieve. - * Use 0 to get the latest message fragment. - * @param last_fragment_id - * Last consecutive fragment ID to retrieve. - * Use 0 to get the latest message fragment. - * @param fragment_limit - * Maximum number of fragments to retrieve. - * @param fragment_cb - * Callback to call with the retrieved fragments. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for the callbacks. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_fragment_get_latest (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - uint64_t fragment_limit, - GNUNET_PSYCSTORE_FragmentCallback fragment_cb, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls); - - -/** - * Retrieve all fragments of messages in a message ID range. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param slave_key - * The slave requesting the message. - * If not NULL, a membership test is performed first - * and the message is only returned if the slave has access to it. - * @param first_message_id - * First message ID to retrieve. - * @param last_message_id - * Last consecutive message ID to retrieve. - * @param fragment_limit - * Maximum number of fragments to retrieve. - * @param method_prefix - * Retrieve only messages with a matching method prefix. - * @param fragment_cb - * Callback to call with the retrieved fragments. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for the callbacks. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_message_get (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - uint64_t first_message_id, - uint64_t last_message_id, - uint64_t fragment_limit, - const char *method_prefix, - GNUNET_PSYCSTORE_FragmentCallback fragment_cb, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls); - - -/** - * Retrieve all fragments of the latest messages. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param slave_key - * The slave requesting the message. - * If not NULL, a membership test is performed first - * and the message is only returned if the slave has access to it. - * @param message_limit - * Maximum number of messages to retrieve. - * @param method_prefix - * Retrieve only messages with a matching method prefix. - * @param fragment_cb - * Callback to call with the retrieved fragments. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for the callbacks. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_message_get_latest (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - uint64_t message_limit, - const char *method_prefix, - GNUNET_PSYCSTORE_FragmentCallback fragment_cb, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls); - - -/** - * Retrieve a fragment of message specified by its message ID and fragment - * offset. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param slave_key - * The slave requesting the message fragment. If not NULL, a membership - * test is performed first and the message fragment is only returned - * if the slave has access to it. - * @param message_id - * Message ID to retrieve. Use 0 to get the latest message. - * @param fragment_offset - * Offset of the fragment to retrieve. - * @param fragment_cb - * Callback to call with the retrieved fragments. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for the callbacks. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_message_get_fragment (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - uint64_t message_id, - uint64_t fragment_offset, - GNUNET_PSYCSTORE_FragmentCallback fragment_cb, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls); - - -/** - * Callback used to return the latest value of counters for the channel master. - * - * @see GNUNET_PSYCSTORE_counters_get() - * - * @param cls Closure. - * @param result_code - * Status code for the operation: - * #GNUNET_OK: success, counter values are returned. - * #GNUNET_NO: no message has been sent to the channel yet. - * #GNUNET_SYSERR: an error occurred. - * @param max_fragment_id - * Latest message fragment ID, used by multicast. - * @param max_message_id - * Latest message ID, used by PSYC. - * @param max_group_generation - * Latest group generation, used by PSYC. - * @param max_state_message_id - * Latest message ID containing state modifiers that - * was applied to the state store. Used for the state sync process. - */ -typedef void -(*GNUNET_PSYCSTORE_CountersCallback) (void *cls, - int result_code, - uint64_t max_fragment_id, - uint64_t max_message_id, - uint64_t max_group_generation, - uint64_t max_state_message_id); - - -/** - * Retrieve latest values of counters for a channel. - * - * The current value of counters are needed - * - when a channel master is restarted, so that it can continue incrementing - * the counters from their last value. - * - when a channel slave rejoins and starts the state synchronization process. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * Public key that identifies the channel. - * @param counters_cb - * Callback to call with the result. - * @param cls - * Closure for the @a ccb callback. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_counters_get (struct GNUNET_PSYCSTORE_Handle *h, - struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - GNUNET_PSYCSTORE_CountersCallback counters_cb, - void *cls); - - -/** - * Apply modifiers of a message to the current channel state. - * - * An error is returned if there are missing messages containing state - * operations before the current one. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param message_id - * ID of the message that contains the @a modifiers. - * @param state_delta - * Value of the @e state_delta PSYC header variable of the message. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for the @a result_cb callback. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_state_modify (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id, - uint64_t state_delta, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls); - - -/** - * Store synchronized state. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param max_state_message_id - * ID of the last stateful message before @a state_hash_message_id. - * @param state_hash_message_id - * ID of the message that contains the state_hash PSYC header variable. - * @param modifier_count - * Number of elements in the @a modifiers array. - * @param modifiers - * Full state to store. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for the callback. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_state_sync (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t max_state_message_id, - uint64_t state_hash_message_id, - size_t modifier_count, - const struct GNUNET_PSYC_Modifier *modifiers, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls); - - - -/** - * Reset the state of a channel. - * - * Delete all state variables stored for the given channel. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for the callback. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_state_reset (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey - *channel_key, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls); - - -/** - * Update signed values of state variables in the state store. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param message_id - * Message ID that contained the state @a hash. - * @param hash - * Hash of the serialized full state. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for the callback. - * - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_state_hash_update (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id, - const struct GNUNET_HashCode *hash, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls); - - -/** - * Function called with the value of a state variable. - * - * @param cls - * Closure. - * @param name - * Name of the state variable. A NULL value indicates that there are no more - * state variables to be returned. - * @param value - * Value of the state variable. - * @param value_size - * Number of bytes in @a value. - * - * @return #GNUNET_NO to stop calling this callback with further variables, - * #GNUNET_YES to continue. - */; -typedef int -(*GNUNET_PSYCSTORE_StateCallback) (void *cls, const char *name, - const void *value, uint32_t value_size); - - -/** - * Retrieve the best matching state variable. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param name - * Name of variable to match, the returned variable might be less specific. - * @param state_cb - * Callback to return the matching state variable. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for the callbacks. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_state_get (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const char *name, - GNUNET_PSYCSTORE_StateCallback state_cb, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls); - - -/** - * Retrieve all state variables for a channel with the given prefix. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param name_prefix - * Prefix of state variable names to match. - * @param state_cb - * Callback to return matching state variables. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for the callbacks. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_state_get_prefix (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const char *name_prefix, - GNUNET_PSYCSTORE_StateCallback state_cb, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls); - - -/** - * Cancel an operation. - * - * @param op Handle for the operation to cancel. - */ -int -GNUNET_PSYCSTORE_operation_cancel (struct GNUNET_PSYCSTORE_OperationHandle *op); - - - - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef GNUNET_PSYCSTORE_SERVICE_H */ -#endif - -/** @} */ /* end of group */ diff --git a/src/include/gnunet_social_service.h b/src/include/gnunet_social_service.h deleted file mode 100644 index 7faa336d6..000000000 --- a/src/include/gnunet_social_service.h +++ /dev/null @@ -1,1344 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2013 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later -*/ - -/** - * @author Gabor X Toth - * @author Christian Grothoff - * - * @file - * Social service; implements social interactions through the PSYC service. - */ - -/** @defgroup social Social service -Social interactions through the PSYC service. - -# Overview - -The social service provides an API for social interactions based on a one-to-many messaging model. -It manages subscriptions of applications to places, provides messaging functionality in places, -allows access to the local message history and manages the GNS zone of _egos_ (user identities). - -The service stores private and public keys of subscribed places, as well as files received in subscribed places. - -# Concepts and terminology - -## Ego, Nym - -An _ego_ is an identity of a user, a private-public key pair. -A _nym_ is an identity of another user in the network, identified by its public key. -Each user can have multiple identities. - -struct GNUNET_SOCIAL_Ego and struct GNUNET_SOCIAL_Nym represents one of these identities. - -## Place, Host, Guest - -A _place_ is where social interactions happen. It is owned and created by an _ego_. -Creating a new place happens by an _ego_ entering a new place as a _host_, -where _guests_ can enter later to receive messages sent to the place. - -A place is identified by its public key. - -- struct GNUNET_SOCIAL_Host represents a place entered as host, -- struct GNUNET_SOCIAL_Guest is used for a place entered as guest. -- A struct GNUNET_SOCIAL_Place can be obtained for both a host and guest place - using GNUNET_SOCIAL_host_get_place() and GNUNET_SOCIAL_guest_get_place() - and can be used with API functions common to hosts and guests. - -## History - -Messages sent to places are stored locally by the PSYCstore service, and can be queried any time. -GNUNET_SOCIAL_history_replay_latest() retrieves the latest N messages sent to the place, -while GNUNET_SOCIAL_history_replay() is used to query a given message ID range. - -## GNU Name System - -The GNU Name System is used for assigning human-readable names to nyms and places. -There's a _GNS zone_ corresponding to each _nym_. -An _ego_ can publish PKEY and PLACE records in its own zone, pointing to nyms and places, respectively. - -## Announcement, talk request - -The host can _announce_ messages to the place, using GNUNET_SOCIAL_host_announce(). -Guests can send _talk_ requests to the host, using GNUNET_SOCIAL_guest_talk(). -The host receives talk requests of guests and can _relay_ them to the place, -or process it using a message handler function. - -# Using the API - -## Connecting to the service - -A client first establishes an _application connection_ to the service using -GNUNET_SOCIAL_app_connect() providing its _application ID_, then receives the -public keys of subscribed places and available egos in response. - -## Reconnecting to places - -Then the application can reconnect to its subscribed places by establishing -_place connections_ with GNUNET_SOCIAL_host_enter_reconnect() and -GNUNET_SOCIAL_guest_enter_reconnect(). - -## Subscribing to a place - -Entering and subscribing a new host or guest place is done using -GNUNET_SOCIAL_host_enter() and GNUNET_SOCIAL_guest_enter(). - -## Disconnecting from a place - -An application can disconnect from a place while the social service keeps its -network connection active, using GNUNET_SOCIAL_host_disconnect() and -GNUNET_SOCIAL_guest_disconnect(). - -## Leaving a place - -To permanently leave a place, see GNUNET_SOCIAL_host_leave() and GNUNET_SOCIAL_guest_leave(). -When leaving a place its network connections are closed and all applications are unsubscribed from the place. - -# Message methods - -## _converse - -Human conversation in a private or public place. - -### Environment - -#### _id_reply -Message ID this message is in reply to. - -#### _id_thread -Thread ID, the first message ID in the thread. - -#### _nym_author -Nym of the author. - -FIXME: Are nyms a different data type from egos and person entities? -Do they have a different format than any other entity address? -Questions and thoughts on how to fix this in "questions.org" - -#### _sig_author -Signature of the message body and its variables by the author. - -### Data - -Message body. - -## _notice_place - -Notification about a place. - -TODO: Applications can decide to auto-subscribe to certain places, -e.g. files under a given size. - -### Environment - -#### Using GNS - -##### _gns_place -GNS name of the place in a globally unique .zkey zone - -FIXME: A custom _gns PSYC data type should be avoidable by parsing -and interpreting PSYC uniforms appropriately. -Thoughts on this in "questions.org" - -#### Without GNS - -##### _key_pub_place -Public key of place - -FIXME: _key_pub can't be the data type for GNUnet-specific cryptographic -addressing. Questions and thoughts on how to fix this in "questions.org" - -##### _peer_origin -Peer ID of origin - -##### _list_peer_relays -List of peer IDs of relays - -## _notice_place_file - -Notification about a place hosting a file. - -### Environment - -The environment of _notice_place above, plus the following: - -#### _size_file -Size of file - -#### _type_file -MIME type of file - -#### _name_file -Name of file - -#### _description_file -Description of file - -## _file - -Messages with a _file method contain a file, -which is saved to disk upon reception at the following location: -$GNUNET_DATA_HOME/social/files// - -### Environment - -#### _size_file -Size of file - -#### _type_file -MIME type of file - -#### _name_file -Name of file - -#### _description_file -Description of file - -@{ -*/ - - -#ifndef GNUNET_SOCIAL_SERVICE_H -#define GNUNET_SOCIAL_SERVICE_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include -#include "gnunet_util_lib.h" -#include "gnunet_psyc_util_lib.h" -#include "gnunet_identity_service.h" -#include "gnunet_namestore_service.h" -#include "gnunet_psyc_service.h" - - -/** - * Version number of GNUnet Social API. - */ -#define GNUNET_SOCIAL_VERSION 0x00000000 - -/** - * Maximum size of client ID including '\0' terminator. - */ -#define GNUNET_SOCIAL_APP_MAX_ID_SIZE 256 - -enum GNUNET_SOCIAL_MsgProcFlags { - GNUNET_SOCIAL_MSG_PROC_NONE = 0, - GNUNET_SOCIAL_MSG_PROC_RELAY = 1, - GNUNET_SOCIAL_MSG_PROC_SAVE= 2, -}; - -/** - * Handle for an application. - */ -struct GNUNET_SOCIAL_App; - -/** - * Handle for an ego (own identity) - */ -struct GNUNET_SOCIAL_Ego; - -/** - * Handle for a pseudonym of another user in the network. - */ -struct GNUNET_SOCIAL_Nym; - -/** - * Handle for a place where social interactions happen. - */ -struct GNUNET_SOCIAL_Place; - -/** - * Host handle for a place that we entered. - */ -struct GNUNET_SOCIAL_Host; - -/** - * Guest handle for place that we entered. - */ -struct GNUNET_SOCIAL_Guest; - -/** - * Handle that can be used to reconnect to a place as host. - */ -struct GNUNET_SOCIAL_HostConnection; - -/** - * Handle that can be used to reconnect to a place as guest. - */ -struct GNUNET_SOCIAL_GuestConnection; - -/** - * Notification about an available identity. - * - * @param cls - * Closure. - * @param pub_key - * Public key of ego. - * @param name - * Name of ego. - */ -typedef void -(*GNUNET_SOCIAL_AppEgoCallback) (void *cls, - struct GNUNET_SOCIAL_Ego *ego, - const struct GNUNET_CRYPTO_EcdsaPublicKey *ego_pub_key, - const char *name); - - -/** - * Entry status of a place per application. - */ -enum GNUNET_SOCIAL_AppPlaceState -{ - /** - * The place was once entered by the ego, but left since. - * It's possible to establish a local connection to the place - * without re-entering to fetch history from the PSYCstore. - * @see enum GNUNET_PSYC_SlaveJoinFlags and GNUNET_SOCIAL_guest_enter() - */ - GNUNET_SOCIAL_PLACE_STATE_ARCHIVED = 0, - - /** - * The place is entered by the ego, - * but this application is not subscribed to it. - */ - GNUNET_SOCIAL_PLACE_STATE_ENTERED = 1, - - /** - * The place is entered by the ego and - * and this application is subscribed to it. - */ - GNUNET_SOCIAL_PLACE_STATE_SUBSCRIBED = 2, -}; - - -/** - * Called after receiving initial list of egos and places. - */ -typedef void -(*GNUNET_SOCIAL_AppConnectedCallback) (void *cls); - - -/** - * Notification about a home. - * - * @param cls - * Closure. - * @param hconn - * Host connection, to be used with GNUNET_SOCIAL_host_enter_reconnect() - * @param ego - * Ego used to enter the place. - * @param place_pub_key - * Public key of the place. - * @param place_state - * @see enum GNUNET_SOCIAL_AppPlaceState - */ -typedef void -(*GNUNET_SOCIAL_AppHostPlaceCallback) (void *cls, - struct GNUNET_SOCIAL_HostConnection *hconn, - struct GNUNET_SOCIAL_Ego *ego, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, - enum GNUNET_SOCIAL_AppPlaceState place_state); - -/** - * Notification about a place. - * - * @param cls - * Closure. - * @param gconn - * Guest connection, to be used with GNUNET_SOCIAL_guest_enter_reconnect() - * @param ego - * Ego used to enter the place. - * @param place_pub_key - * Public key of the place. - * @param place_state - * @see enum GNUNET_SOCIAL_AppPlaceState - */ -typedef void -(*GNUNET_SOCIAL_AppGuestPlaceCallback) (void *cls, - struct GNUNET_SOCIAL_GuestConnection *gconn, - struct GNUNET_SOCIAL_Ego *ego, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, - enum GNUNET_SOCIAL_AppPlaceState place_state); - - -/** - * Establish application connection to the social service. - * - * The @host_cb and @guest_cb functions are - * initially called for each entered places, - * then later each time a new place is entered with the current app ID. - * - * @param cfg - * Configuration. - * @param ego_cb - * Function to notify about an available ego. - * @param host_cb - * Function to notify about a place entered as host. - * @param guest_cb - * Function to notify about a place entered as guest. - * @param cls - * Closure for the callbacks. - * - * @return Handle that can be used to stop listening. - */ -struct GNUNET_SOCIAL_App * -GNUNET_SOCIAL_app_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, - const char *id, - GNUNET_SOCIAL_AppEgoCallback ego_cb, - GNUNET_SOCIAL_AppHostPlaceCallback host_cb, - GNUNET_SOCIAL_AppGuestPlaceCallback guest_cb, - GNUNET_SOCIAL_AppConnectedCallback connected_cb, - void *cls); - - -/** - * Disconnect app. - * - * @param app - * Application handle. - * @param disconnect_cb - * Disconnect callback. - * @param disconnect_cls - * Disconnect closure. - */ -void -GNUNET_SOCIAL_app_disconnect (struct GNUNET_SOCIAL_App *app, - GNUNET_ContinuationCallback disconnect_cb, - void *disconnect_cls); - - -/** - * Get the public key of @a ego. - * - * @param ego - * Ego. - * - * @return Public key of ego. - */ -const struct GNUNET_CRYPTO_EcdsaPublicKey * -GNUNET_SOCIAL_ego_get_pub_key (const struct GNUNET_SOCIAL_Ego *ego); - - -/** - * Get the name of @a ego. - * - * @param ego - * Ego. - * - * @return Public key of @a ego. - */ -const char * -GNUNET_SOCIAL_ego_get_name (const struct GNUNET_SOCIAL_Ego *ego); - - -/** - * Get the public key of a @a nym. - * - * Suitable, for example, to be used with GNUNET_SOCIAL_zone_add_nym(). - * - * @param nym - * Pseudonym to map to a cryptographic identifier. - * - * @return Public key of nym. - */ -const struct GNUNET_CRYPTO_EcdsaPublicKey * -GNUNET_SOCIAL_nym_get_pub_key (const struct GNUNET_SOCIAL_Nym *nym); - - -/** - * Get the hash of the public key of a @a nym. - * - * @param nym - * Pseudonym to map to a cryptographic identifier. - * - * @return Hash of the public key of nym. - */ -const struct GNUNET_HashCode * -GNUNET_SOCIAL_nym_get_pub_key_hash (const struct GNUNET_SOCIAL_Nym *nym); - - -/** - * Function called asking for nym to be admitted to the place. - * - * Should call either GNUNET_SOCIAL_host_admit() or - * GNUNET_SOCIAL_host_reject_entry() (possibly asynchronously). If this host - * cannot decide, it is fine to call neither function, in which case hopefully - * some other host of the place exists that will make the decision. The @a nym - * reference remains valid until the #GNUNET_SOCIAL_FarewellCallback is invoked - * for it. - * - * @param cls - * Closure. - * @param nym - * Handle for the user who wants to enter. - * @param method_name - * Method name in the entry request. - * @param variable_count - * Number of elements in the @a variables array. - * @param variables - * Variables present in the message. - * @param data - * Payload given on enter (e.g. a password). - * @param data_size - * Number of bytes in @a data. - */ -typedef void -(*GNUNET_SOCIAL_AnswerDoorCallback) (void *cls, - struct GNUNET_SOCIAL_Nym *nym, - const char *method_name, - struct GNUNET_PSYC_Environment *env, - const void *data, - size_t data_size); - - -/** - * Function called when a @a nym leaves the place. - * - * This is also called if the @a nym was never given permission to enter - * (i.e. the @a nym stopped asking to get in). - * - * @param cls - * Closure. - * @param nym - * Handle for the user who left. - */ -typedef void -(*GNUNET_SOCIAL_FarewellCallback) (void *cls, - const struct GNUNET_SOCIAL_Nym *nym, - struct GNUNET_PSYC_Environment *env); - - -/** - * Function called after the host entered a home. - * - * @param cls - * Closure. - * @param result - * #GNUNET_OK on success, or - * #GNUNET_SYSERR on error. - * @param place_pub_key - * Public key of home. - * @param max_message_id - * Last message ID sent to the channel. - * Or 0 if no messages have been sent to the place yet. - */ -typedef void -(*GNUNET_SOCIAL_HostEnterCallback) (void *cls, int result, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, - uint64_t max_message_id); - - -/** - * Enter a place as host. - * - * A place is created upon first entering, and it is active until permanently - * left using GNUNET_SOCIAL_host_leave(). - * - * @param cfg - * Configuration to contact the social service. - * @param ego - * Identity of the host. - * @param place_key - * Private-public key pair of the place. - * NULL for ephemeral places. - * @param policy - * Policy specifying entry and history restrictions for the place. - * @param slicer - * Slicer to handle incoming messages. - * @param enter_cb - * Function called when the place is entered and ready to use. - * @param answer_door_cb - * Function to handle new nyms that want to enter. - * @param farewell_cb - * Function to handle departing nyms. - * @param cls - * Closure for the callbacks. - * - * @return Handle for the host. - */ -struct GNUNET_SOCIAL_Host * -GNUNET_SOCIAL_host_enter (const struct GNUNET_SOCIAL_App *app, - const struct GNUNET_SOCIAL_Ego *ego, - enum GNUNET_PSYC_Policy policy, - struct GNUNET_PSYC_Slicer *slicer, - GNUNET_SOCIAL_HostEnterCallback enter_cb, - GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb, - GNUNET_SOCIAL_FarewellCallback farewell_cb, - void *cls); - - -/** - * Reconnect to an already entered place as host. - * - * @param hconn - * Host connection handle. - * @see GNUNET_SOCIAL_app_connect() & GNUNET_SOCIAL_AppHostPlaceCallback() - * @param slicer - * Slicer to handle incoming messages. - * @param enter_cb - * Function called when the place is entered and ready to use. - * @param answer_door_cb - * Function to handle new nyms that want to enter. - * @param farewell_cb - * Function to handle departing nyms. - * @param cls - * Closure for the callbacks. - * - * @return Handle for the host. - */ -struct GNUNET_SOCIAL_Host * -GNUNET_SOCIAL_host_enter_reconnect (struct GNUNET_SOCIAL_HostConnection *hconn, - struct GNUNET_PSYC_Slicer *slicer, - GNUNET_SOCIAL_HostEnterCallback enter_cb, - GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb, - GNUNET_SOCIAL_FarewellCallback farewell_cb, - void *cls); - - -/** - * Decision whether to admit @a nym into the place or refuse entry. - * - * @param hst - * Host of the place. - * @param nym - * Handle for the entity that wanted to enter. - * @param is_admitted - * #GNUNET_YES if @a nym is admitted, - * #GNUNET_NO if @a nym is refused entry, - * #GNUNET_SYSERR if we cannot answer the request. - * @param entry_resp - * Entry response message, or NULL. - * @return #GNUNET_OK on success, - * #GNUNET_SYSERR if the message is too large. - */ -int -GNUNET_SOCIAL_host_entry_decision (struct GNUNET_SOCIAL_Host *hst, - struct GNUNET_SOCIAL_Nym *nym, - int is_admitted, - const struct GNUNET_PSYC_Message *entry_resp); - - -/** - * Throw @a nym out of the place. - * - * Sends a _notice_place_leave announcement to the home. - * - * The @a nym reference will remain valid until the - * #GNUNET_SOCIAL_FarewellCallback is invoked, - * which should be very soon after this call. - * - * @param host - * Host of the place. - * @param nym - * Handle for the entity to be ejected. - * @param env - * Environment for the message or NULL. - * _nym is set to @e nym regardless whether an @e env is provided. - */ -void -GNUNET_SOCIAL_host_eject (struct GNUNET_SOCIAL_Host *host, - const struct GNUNET_SOCIAL_Nym *nym, - struct GNUNET_PSYC_Environment *env); - - -/** - * Flags for announcements by a host. - */ -enum GNUNET_SOCIAL_AnnounceFlags -{ - GNUNET_SOCIAL_ANNOUNCE_NONE = 0, - - /** - * Whether this announcement removes all objects from the place. - * - * New objects can be still added to the now empty place using the @e env - * parameter of the same announcement. - */ - GNUNET_SOCIAL_ANNOUNCE_CLEAR_OBJECTS = 1 << 0 -}; - - -/** - * Handle for an announcement request. - */ -struct GNUNET_SOCIAL_Announcement; - - -/** - * Send a message to all nyms that are present in the place. - * - * This function is restricted to the host. Nyms can only send requests - * to the host who can decide to relay it to everyone in the place. - * - * @param host - * Host of the place. - * @param method_name - * Method to use for the announcement. - * @param env - * Environment containing variables for the message and operations - * on objects of the place. - * Has to remain available until the first call to @a notify_data. - * Can be NULL. - * @param notify_data - * Function to call to get the payload of the announcement. - * @param notify_data_cls - * Closure for @a notify. - * @param flags - * Flags for this announcement. - * - * @return NULL on error (another announcement already in progress?). - */ -struct GNUNET_SOCIAL_Announcement * -GNUNET_SOCIAL_host_announce (struct GNUNET_SOCIAL_Host *host, - const char *method_name, - const struct GNUNET_PSYC_Environment *env, - GNUNET_PSYC_TransmitNotifyData notify_data, - void *notify_data_cls, - enum GNUNET_SOCIAL_AnnounceFlags flags); - - -/** - * Resume transmitting announcement. - * - * @param a - * The announcement to resume. - */ -void -GNUNET_SOCIAL_host_announce_resume (struct GNUNET_SOCIAL_Announcement *a); - - -/** - * Cancel announcement. - * - * @param a - * The announcement to cancel. - */ -void -GNUNET_SOCIAL_host_announce_cancel (struct GNUNET_SOCIAL_Announcement *a); - - -/** - * Allow relaying messages from guests matching a given @a method_prefix. - * - * @param host - * The host. - * @param method_prefix - * Method prefix to allow. - */ -void -GNUNET_SOCIAL_host_relay_allow_method (struct GNUNET_SOCIAL_Host *host, - const char *method_prefix); - - -/** - * Allow relaying changes to objects of the place. - * - * Only applies to messages with an allowed method name. - * @see GNUNET_SCOIAL_host_relay_allow_method() - * - * @param host - * The host. - * @param object_prefix - * Object prefix to allow modifying. - */ -void -GNUNET_SOCIAL_host_relay_allow_method (struct GNUNET_SOCIAL_Host *host, - const char *object_prefix); - - -/** - * Stop relaying messages from guests. - * - * Remove all allowed relay rules. - * - * - * - */ -void -GNUNET_SOCIAL_host_relay_stop (struct GNUNET_SOCIAL_Host *host); - - -/** - * Obtain handle for a hosted place. - * - * The returned handle can be used to access the place API. - * - * @param host - * Handle for the host. - * - * @return Handle for the hosted place, valid as long as @a host is valid. - */ -struct GNUNET_SOCIAL_Place * -GNUNET_SOCIAL_host_get_place (struct GNUNET_SOCIAL_Host *host); - - -/** - * Disconnect from a home. - * - * Invalidates host handle. - * - * @param hst - * The host to disconnect. - * @param disconnect_cb - * Function called after disconnected from the service. - * @param cls - * Closure for @a disconnect_cb. - */ -void -GNUNET_SOCIAL_host_disconnect (struct GNUNET_SOCIAL_Host *hst, - GNUNET_ContinuationCallback disconnect_cb, - void *cls); - - -/** - * Stop hosting a home. - * - * Sends a _notice_place_closing announcement to the home. - * Invalidates host handle. - * - * @param hst - * Host leaving. - * @param env - * Environment for the message or NULL. - * @param disconnect_cb - * Function called after the host left the place - * and disconnected from the service. - * @param cls - * Closure for @a disconnect_cb. - */ -void -GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *hst, - const struct GNUNET_PSYC_Environment *env, - GNUNET_ContinuationCallback disconnect_cb, - void *cls); - - -/** - * Function called after the guest entered the local copy of the place. - * - * History and object query functions can be used after this call, - * but new messages can't be sent or received. - * - * @param cls - * Closure. - * @param result - * #GNUNET_OK on success, or - * #GNUNET_SYSERR on error, e.g. could not connect to the service, or - * could not resolve GNS name. - * @param place_pub_key - * Public key of place. - * @param max_message_id - * Last message ID sent to the place. - * Or 0 if no messages have been sent to the place yet. - */ -typedef void -(*GNUNET_SOCIAL_GuestEnterCallback) (void *cls, int result, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, - uint64_t max_message_id); - - -/** - * Function called upon a guest receives a decision about entry to the place. - * - * @param is_admitted - * Is the guest admitted to the place? - * #GNUNET_YES if admitted, - * #GNUNET_NO if refused entry, - * #GNUNET_SYSERR if the request could not be answered. - * @param data - * Entry response message. - */ -typedef void -(*GNUNET_SOCIAL_EntryDecisionCallback) (void *cls, - int is_admitted, - const struct GNUNET_PSYC_Message *entry_resp); - - -/** - * Request entry to a place as a guest. - * - * @param app - * Application handle. - * @param ego - * Identity of the guest. - * @param place_pub_key - * Public key of the place to enter. - * @param flags - * Flags for the entry. - * @param origin - * Peer identity of the origin of the underlying multicast group. - * @param relay_count - * Number of elements in the @a relays array. - * @param relays - * Relays for the underlying multicast group. - * @param entry_msg - * Entry message. - * @param slicer - * Slicer to use for processing incoming requests from guests. - * - * @return NULL on errors, otherwise handle for the guest. - */ -struct GNUNET_SOCIAL_Guest * -GNUNET_SOCIAL_guest_enter (const struct GNUNET_SOCIAL_App *app, - const struct GNUNET_SOCIAL_Ego *ego, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, - enum GNUNET_PSYC_SlaveJoinFlags flags, - const struct GNUNET_PeerIdentity *origin, - uint32_t relay_count, - const struct GNUNET_PeerIdentity *relays, - const struct GNUNET_PSYC_Message *entry_msg, - struct GNUNET_PSYC_Slicer *slicer, - GNUNET_SOCIAL_GuestEnterCallback local_enter_cb, - GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb, - void *cls); - - -/** - * Request entry to a place by name as a guest. - * - * @param app - * Application handle. - * @param ego - * Identity of the guest. - * @param gns_name - * GNS name of the place to enter. Either in the form of - * 'room.friend.gnu', or 'NYMPUBKEY.zkey'. This latter case refers to - * the 'PLACE' record of the empty label ("+") in the GNS zone with the - * nym's public key 'NYMPUBKEY', and can be used to request entry to a - * pseudonym's place directly. - * @param password - * Password to decrypt the record, or NULL for cleartext records. - * @param join_msg - * Entry request message. - * @param slicer - * Slicer to use for processing incoming requests from guests. - * @param local_enter_cb - * Called upon connection established to the social service. - * @param entry_decision_cb - * Called upon receiving entry decision. - * - * @return NULL on errors, otherwise handle for the guest. - */ -struct GNUNET_SOCIAL_Guest * -GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_SOCIAL_App *app, - const struct GNUNET_SOCIAL_Ego *ego, - const char *gns_name, - const char *password, - const struct GNUNET_PSYC_Message *join_msg, - struct GNUNET_PSYC_Slicer *slicer, - GNUNET_SOCIAL_GuestEnterCallback local_enter_cb, - GNUNET_SOCIAL_EntryDecisionCallback entry_decision_cb, - void *cls); - - -/** - * Reconnect to an already entered place as guest. - * - * @param gconn - * Guest connection handle. - * @see GNUNET_SOCIAL_app_connect() & GNUNET_SOCIAL_AppGuestPlaceCallback() - * @param flags - * Flags for the entry. - * @param slicer - * Slicer to use for processing incoming requests from guests. - * @param local_enter_cb - * Called upon connection established to the social service. - * @param entry_decision_cb - * Called upon receiving entry decision. - * - * @return NULL on errors, otherwise handle for the guest. - */ -struct GNUNET_SOCIAL_Guest * -GNUNET_SOCIAL_guest_enter_reconnect (struct GNUNET_SOCIAL_GuestConnection *gconn, - enum GNUNET_PSYC_SlaveJoinFlags flags, - struct GNUNET_PSYC_Slicer *slicer, - GNUNET_SOCIAL_GuestEnterCallback local_enter_cb, - void *cls); - - -/** - * Flags for talking to the host of a place. - */ -enum GNUNET_SOCIAL_TalkFlags -{ - GNUNET_SOCIAL_TALK_NONE = 0 -}; - - -/** - * A talk request. - */ -struct GNUNET_SOCIAL_TalkRequest; - - -/** - * Talk to the host of the place. - * - * @param place - * Place where we want to talk to the host. - * @param method_name - * Method to invoke on the host. - * @param env - * Environment containing variables for the message, or NULL. - * @param notify_data - * Function to use to get the payload for the method. - * @param notify_data_cls - * Closure for @a notify_data. - * @param flags - * Flags for the message being sent. - * - * @return NULL if we are already trying to talk to the host, - * otherwise handle to cancel the request. - */ -struct GNUNET_SOCIAL_TalkRequest * -GNUNET_SOCIAL_guest_talk (struct GNUNET_SOCIAL_Guest *guest, - const char *method_name, - const struct GNUNET_PSYC_Environment *env, - GNUNET_PSYC_TransmitNotifyData notify_data, - void *notify_data_cls, - enum GNUNET_SOCIAL_TalkFlags flags); - - -/** - * Resume talking to the host of the place. - * - * @param tr - * Talk request to resume. - */ -void -GNUNET_SOCIAL_guest_talk_resume (struct GNUNET_SOCIAL_TalkRequest *tr); - - -/** - * Cancel talking to the host of the place. - * - * @param tr - * Talk request to cancel. - */ -void -GNUNET_SOCIAL_guest_talk_cancel (struct GNUNET_SOCIAL_TalkRequest *tr); - - -/** - * Disconnect from a place. - * - * Invalidates guest handle. - * - * @param gst - * The guest to disconnect. - * @param disconnect_cb - * Function called after disconnected from the service. - * @param cls - * Closure for @a disconnect_cb. - */ -void -GNUNET_SOCIAL_guest_disconnect (struct GNUNET_SOCIAL_Guest *gst, - GNUNET_ContinuationCallback disconnect_cb, - void *cls); - - -/** - * Leave a place temporarily or permanently. - * - * Notifies the owner of the place about leaving, and destroys the place handle. - * - * @param place - * Place to leave. - * @param env - * Optional environment for the leave message if @a keep_active - * is #GNUNET_NO. NULL if not needed. - * @param disconnect_cb - * Called upon disconnecting from the social service. - */ -void -GNUNET_SOCIAL_guest_leave (struct GNUNET_SOCIAL_Guest *gst, - struct GNUNET_PSYC_Environment *env, - GNUNET_ContinuationCallback disconnect_cb, - void *leave_cls); - - -/** - * Obtain handle for a place entered as guest. - * - * The returned handle can be used to access the place API. - * - * @param guest Handle for the guest. - * - * @return Handle for the place, valid as long as @a guest is valid. - */ -struct GNUNET_SOCIAL_Place * -GNUNET_SOCIAL_guest_get_place (struct GNUNET_SOCIAL_Guest *guest); - - -/** - * A history request. - */ -struct GNUNET_SOCIAL_HistoryRequest; - - -/** - * Get the public key of a place. - * - * @param plc - * Place. - * - * @return Public key of the place. - */ -const struct GNUNET_CRYPTO_EddsaPublicKey * -GNUNET_SOCIAL_place_get_pub_key (const struct GNUNET_SOCIAL_Place *plc); - - -/** - * Set message processing @a flags for a @a method_prefix. - * - * @param plc - * Place. - * @param method_prefix - * Method prefix @a flags apply to. - * @param flags - * The flags that apply to a matching @a method_prefix. - */ -void -GNUNET_SOCIAL_place_msg_proc_set (struct GNUNET_SOCIAL_Place *plc, - const char *method_prefix, - enum GNUNET_SOCIAL_MsgProcFlags flags); - -/** - * Clear all message processing flags previously set for this place. - */ -void -GNUNET_SOCIAL_place_msg_proc_clear (struct GNUNET_SOCIAL_Place *plc); - - -/** - * Learn about the history of a place. - * - * Messages are returned through the @a slicer function - * and have the #GNUNET_PSYC_MESSAGE_HISTORIC flag set. - * - * @param place - * Place we want to learn more about. - * @param start_message_id - * First historic message we are interested in. - * @param end_message_id - * Last historic message we are interested in (inclusive). - * @param method_prefix - * Only retrieve messages with this method prefix. - * @param flags - * OR'ed GNUNET_PSYC_HistoryReplayFlags - * @param slicer - * Slicer to use for retrieved messages. - * Can be the same as the slicer of the place. - * @param result_cb - * Function called after all messages retrieved. - * NULL if not needed. - * @param cls Closure for @a result_cb. - */ -struct GNUNET_SOCIAL_HistoryRequest * -GNUNET_SOCIAL_place_history_replay (struct GNUNET_SOCIAL_Place *plc, - uint64_t start_message_id, - uint64_t end_message_id, - const char *method_prefix, - uint32_t flags, - struct GNUNET_PSYC_Slicer *slicer, - GNUNET_ResultCallback result_cb, - void *cls); - - -/** - * Learn about the history of a place. - * - * Sends messages through the slicer function of the place where - * start_message_id <= message_id <= end_message_id. - * The messages will have the #GNUNET_PSYC_MESSAGE_HISTORIC flag set. - * - * To get the latest message, use 0 for both the start and end message ID. - * - * @param place - * Place we want to learn more about. - * @param message_limit - * Maximum number of historic messages we are interested in. - * @param result_cb - * Function called after all messages retrieved. - * NULL if not needed. - * @param cls Closure for @a result_cb. - */ -struct GNUNET_SOCIAL_HistoryRequest * -GNUNET_SOCIAL_place_history_replay_latest (struct GNUNET_SOCIAL_Place *plc, - uint64_t message_limit, - const char *method_prefix, - uint32_t flags, - struct GNUNET_PSYC_Slicer *slicer, - GNUNET_ResultCallback result_cb, - void *cls); - -/** - * Cancel learning about the history of a place. - * - * @param hist - * History lesson to cancel. - */ -void -GNUNET_SOCIAL_place_history_replay_cancel (struct GNUNET_SOCIAL_HistoryRequest *hist); - - -struct GNUNET_SOCIAL_LookHandle; - - -/** - * Look at a particular object in the place. - * - * The best matching object is returned (its name might be less specific than - * what was requested). - * - * @param place - * The place to look the object at. - * @param full_name - * Full name of the object. - * - * @return NULL if there is no such object at this place. - */ -struct GNUNET_SOCIAL_LookHandle * -GNUNET_SOCIAL_place_look_at (struct GNUNET_SOCIAL_Place *plc, - const char *full_name, - GNUNET_PSYC_StateVarCallback var_cb, - GNUNET_ResultCallback result_cb, - void *cls); - -/** - * Look for objects in the place with a matching name prefix. - * - * @param place - * The place to look its objects at. - * @param name_prefix - * Look at objects with names beginning with this value. - * @param var_cb - * Function to call for each object found. - * @param cls - * Closure for callback function. - * - * @return Handle that can be used to stop looking at objects. - */ -struct GNUNET_SOCIAL_LookHandle * -GNUNET_SOCIAL_place_look_for (struct GNUNET_SOCIAL_Place *plc, - const char *name_prefix, - GNUNET_PSYC_StateVarCallback var_cb, - GNUNET_ResultCallback result_cb, - void *cls); - - -/** - * Stop looking at objects. - * - * @param lh Look handle to stop. - */ -void -GNUNET_SOCIAL_place_look_cancel (struct GNUNET_SOCIAL_LookHandle *lh); - - -/** - * Advertise a @e place in the GNS zone of @a ego. - * - * @param app - * Application handle. - * @param ego - * Ego. - * @param place_pub_key - * Public key of place to add. - * @param name - * The name for the PLACE record to put in the zone. - * @param password - * Password used to encrypt the record or NULL to keep it cleartext. - * @param relay_count - * Number of elements in the @a relays array. - * @param relays - * List of relays to put in the PLACE record to advertise - * as entry points to the place in addition to the origin. - * @param expiration_time - * Expiration time of the record, use 0 to remove the record. - * @param result_cb - * Function called with the result of the operation. - * @param result_cls - * Closure for @a result_cb - * - * @return #GNUNET_OK if the request was sent, - * #GNUNET_SYSERR on error, e.g. the name/password is too long. - */ -int -GNUNET_SOCIAL_zone_add_place (const struct GNUNET_SOCIAL_App *app, - const struct GNUNET_SOCIAL_Ego *ego, - const char *name, - const char *password, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, - const struct GNUNET_PeerIdentity *origin, - uint32_t relay_count, - const struct GNUNET_PeerIdentity *relays, - struct GNUNET_TIME_Absolute expiration_time, - GNUNET_ResultCallback result_cb, - void *result_cls); - - -/** - * Add public key to the GNS zone of the @e ego. - * - * @param cfg - * Configuration. - * @param ego - * Ego. - * @param name - * The name for the PKEY record to put in the zone. - * @param nym_pub_key - * Public key of nym to add. - * @param expiration_time - * Expiration time of the record, use 0 to remove the record. - * @param result_cb - * Function called with the result of the operation. - * @param result_cls - * Closure for @a result_cb - * - * @return #GNUNET_OK if the request was sent, - * #GNUNET_SYSERR on error, e.g. the name is too long. - */ -int -GNUNET_SOCIAL_zone_add_nym (const struct GNUNET_SOCIAL_App *app, - const struct GNUNET_SOCIAL_Ego *ego, - const char *name, - const struct GNUNET_CRYPTO_EcdsaPublicKey *nym_pub_key, - struct GNUNET_TIME_Absolute expiration_time, - GNUNET_ResultCallback result_cb, - void *result_cls); - - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef GNUNET_SOCIAL_SERVICE_H */ -#endif - -/** @} */ /* end of group */ diff --git a/src/multicast/.gitignore b/src/multicast/.gitignore deleted file mode 100644 index a97844e81..000000000 --- a/src/multicast/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -gnunet-service-multicast -gnunet-multicast -test_multicast -test_multicast_multipeer -test_multicast_2peers -test_multicast_multipeer_line -test_multicast_multipeer_star diff --git a/src/multicast/Makefile.am b/src/multicast/Makefile.am deleted file mode 100644 index 61a9f8bf6..000000000 --- a/src/multicast/Makefile.am +++ /dev/null @@ -1,79 +0,0 @@ -# This Makefile.am is in the public domain -AM_CPPFLAGS = -I$(top_srcdir)/src/include - -pkgcfgdir= $(pkgdatadir)/config.d/ - -libexecdir= $(pkglibdir)/libexec/ - -pkgcfg_DATA = \ - multicast.conf - -if MINGW - WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -endif - -if USE_COVERAGE - AM_CFLAGS = -fprofile-arcs -ftest-coverage -endif - -lib_LTLIBRARIES = libgnunetmulticast.la - -libgnunetmulticast_la_SOURCES = \ - multicast_api.c multicast.h -libgnunetmulticast_la_LIBADD = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(GN_LIBINTL) $(XLIB) -libgnunetmulticast_la_LDFLAGS = \ - $(GN_LIB_LDFLAGS) $(WINFLAGS) \ - -version-info 0:0:0 - - -bin_PROGRAMS = \ - gnunet-multicast - -libexec_PROGRAMS = \ - gnunet-service-multicast \ - $(EXP_LIBEXEC) - -gnunet_multicast_SOURCES = \ - gnunet-multicast.c -gnunet_multicast_LDADD = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(GN_LIBINTL) - -gnunet_service_multicast_SOURCES = \ - gnunet-service-multicast.c -gnunet_service_multicast_LDADD = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/cadet/libgnunetcadet.la \ - $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(GN_LIBINTL) - -check_PROGRAMS = \ - test_multicast \ - test_multicast_multipeer_star \ - test_multicast_multipeer_line - -if ENABLE_TEST_RUN -AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@}; export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; unset XDG_DATA_HOME; unset XDG_CONFIG_HOME; -TESTS = $(check_PROGRAMS) -endif - -test_multicast_SOURCES = \ - test_multicast.c -test_multicast_LDADD = \ - libgnunetmulticast.la \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/util/libgnunetutil.la -test_multicast_multipeer_star_SOURCES = \ - test_multicast_multipeer.c -test_multicast_multipeer_star_LDADD = \ - libgnunetmulticast.la \ - $(top_builddir)/src/testbed/libgnunettestbed.la \ - $(top_builddir)/src/util/libgnunetutil.la -test_multicast_multipeer_line_SOURCES = \ - test_multicast_multipeer.c -test_multicast_multipeer_line_LDADD = \ - libgnunetmulticast.la \ - $(top_builddir)/src/testbed/libgnunettestbed.la \ - $(top_builddir)/src/util/libgnunetutil.la diff --git a/src/multicast/gnunet-multicast.c b/src/multicast/gnunet-multicast.c deleted file mode 100644 index 63e1d52aa..000000000 --- a/src/multicast/gnunet-multicast.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2013 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later -*/ - -/** - * @file multicast/gnunet-multicast.c - * @brief multicast for writing a tool - * @author Christian Grothoff - */ -#include "platform.h" -#include "gnunet_util_lib.h" -/* #include "gnunet_multicast_service.h" */ - -/** - * Final status code. - */ -static int ret; - -/** - * Main function that will be run by the scheduler. - * - * @param cls closure - * @param args remaining command-line arguments - * @param cfgfile name of the configuration file used (for saving, can be NULL!) - * @param cfg configuration - */ -static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - /* main code here */ - puts( gettext_noop ("This command doesn't do anything yet.") ); - ret = -1; -} - - -/** - * The main function. - * - * @param argc number of arguments from the command line - * @param argv command line arguments - * @return 0 ok, 1 on error - */ -int -main (int argc, char *const *argv) -{ - static const struct GNUNET_GETOPT_CommandLineOption options[] = { - /* FIMXE: add options here */ - GNUNET_GETOPT_OPTION_END - }; - if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) - return 2; - - ret = (GNUNET_OK == - GNUNET_PROGRAM_run (argc, argv, "gnunet-multicast", - gettext_noop ("This command doesn't do anything yet."), - options, &run, - NULL)) ? ret : 1; - GNUNET_free ((void*) argv); - return ret; -} - -/* end of gnunet-multicast.c */ diff --git a/src/multicast/gnunet-service-multicast.c b/src/multicast/gnunet-service-multicast.c deleted file mode 100644 index 18c366118..000000000 --- a/src/multicast/gnunet-service-multicast.c +++ /dev/null @@ -1,2234 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2009 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later -*/ - -/** - * @file multicast/gnunet-service-multicast.c - * @brief program that does multicast - * @author Christian Grothoff - */ -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_signatures.h" -#include "gnunet_applications.h" -#include "gnunet_statistics_service.h" -#include "gnunet_cadet_service.h" -#include "gnunet_multicast_service.h" -#include "multicast.h" - -/** - * Handle to our current configuration. - */ -static const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * Service handle. - */ -static struct GNUNET_SERVICE_Handle *service; - -/** - * CADET handle. - */ -static struct GNUNET_CADET_Handle *cadet; - -/** - * Identity of this peer. - */ -static struct GNUNET_PeerIdentity this_peer; - -/** - * Handle to the statistics service. - */ -static struct GNUNET_STATISTICS_Handle *stats; - -/** - * All connected origin clients. - * Group's pub_key_hash -> struct Origin * (uniq) - */ -static struct GNUNET_CONTAINER_MultiHashMap *origins; - -/** - * All connected member clients. - * Group's pub_key_hash -> struct Member * (multi) - */ -static struct GNUNET_CONTAINER_MultiHashMap *members; - -/** - * Connected member clients per group. - * Group's pub_key_hash -> Member's pub_key_hash (uniq) -> struct Member * (uniq) - */ -static struct GNUNET_CONTAINER_MultiHashMap *group_members; - -/** - * Incoming CADET channels with connected children in the tree. - * Group's pub_key_hash -> struct Channel * (multi) - */ -static struct GNUNET_CONTAINER_MultiHashMap *channels_in; - -/** - * Outgoing CADET channels connecting to parents in the tree. - * Group's pub_key_hash -> struct Channel * (multi) - */ -static struct GNUNET_CONTAINER_MultiHashMap *channels_out; - -/** - * Incoming replay requests from CADET. - * Group's pub_key_hash -> - * H(fragment_id, message_id, fragment_offset, flags) -> struct Channel * - */ -static struct GNUNET_CONTAINER_MultiHashMap *replay_req_cadet; - -/** - * Incoming replay requests from clients. - * Group's pub_key_hash -> - * H(fragment_id, message_id, fragment_offset, flags) -> struct GNUNET_SERVICE_Client * - */ -static struct GNUNET_CONTAINER_MultiHashMap *replay_req_client; - - -/** - * Join status of a remote peer. - */ -enum JoinStatus -{ - JOIN_REFUSED = -1, - JOIN_NOT_ASKED = 0, - JOIN_WAITING = 1, - JOIN_ADMITTED = 2, -}; - -enum ChannelDirection -{ - DIR_INCOMING = 0, - DIR_OUTGOING = 1, -}; - - -/** - * Context for a CADET channel. - */ -struct Channel -{ - /** - * Group the channel belongs to. - * - * Only set for outgoing channels. - */ - struct Group *group; - - /** - * CADET channel. - */ - struct GNUNET_CADET_Channel *channel; - - // FIXME: not used - /** - * CADET transmission handle. - */ - struct GNUNET_CADET_TransmitHandle *tmit_handle; - - /** - * Public key of the target group. - */ - struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key; - - /** - * Hash of @a group_pub_key. - */ - struct GNUNET_HashCode group_pub_hash; - - /** - * Public key of the joining member. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; - - /** - * Remote peer identity. - */ - struct GNUNET_PeerIdentity peer; - - /** - * Current window size, set by cadet_notify_window_change() - */ - int32_t window_size; - - /** - * Is the connection established? - */ - int8_t is_connected; - - /** - * Is the remote peer admitted to the group? - * @see enum JoinStatus - */ - int8_t join_status; - - /** - * Number of messages waiting to be sent to CADET. - */ - uint8_t msgs_pending; - - /** - * Channel direction. - * @see enum ChannelDirection - */ - uint8_t direction; -}; - - -/** - * List of connected clients. - */ -struct ClientList -{ - struct ClientList *prev; - struct ClientList *next; - struct GNUNET_SERVICE_Client *client; -}; - - -/** - * Client context for an origin or member. - */ -struct Group -{ - struct ClientList *clients_head; - struct ClientList *clients_tail; - - /** - * Public key of the group. - */ - struct GNUNET_CRYPTO_EddsaPublicKey pub_key; - - /** - * Hash of @a pub_key. - */ - struct GNUNET_HashCode pub_key_hash; - - /** - * CADET port hash. - */ - struct GNUNET_HashCode cadet_port_hash; - - /** - * Is the client disconnected? #GNUNET_YES or #GNUNET_NO - */ - uint8_t is_disconnected; - - /** - * Is this an origin (#GNUNET_YES), or member (#GNUNET_NO)? - */ - uint8_t is_origin; - - union { - struct Origin *origin; - struct Member *member; - }; -}; - - -/** -* Client context for a group's origin. - */ -struct Origin -{ - struct Group group; - - /** - * Private key of the group. - */ - struct GNUNET_CRYPTO_EddsaPrivateKey priv_key; - - /** - * CADET port. - */ - struct GNUNET_CADET_Port *cadet_port; - - /** - * Last message fragment ID sent to the group. - */ - uint64_t max_fragment_id; -}; - - -/** - * Client context for a group member. - */ -struct Member -{ - struct Group group; - - /** - * Private key of the member. - */ - struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key; - - /** - * Public key of the member. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; - - /** - * Hash of @a pub_key. - */ - struct GNUNET_HashCode pub_key_hash; - - /** - * Join request sent to the origin / members. - */ - struct MulticastJoinRequestMessage *join_req; - - /** - * Join decision sent in reply to our request. - * - * Only a positive decision is stored here, in case of a negative decision the - * client is disconnected. - */ - struct MulticastJoinDecisionMessageHeader *join_dcsn; - - /** - * CADET channel to the origin. - */ - struct Channel *origin_channel; - - /** - * Peer identity of origin. - */ - struct GNUNET_PeerIdentity origin; - - /** - * Peer identity of relays (other members to connect). - */ - struct GNUNET_PeerIdentity *relays; - - /** - * Last request fragment ID sent to the origin. - */ - uint64_t max_fragment_id; - - /** - * Number of @a relays. - */ - uint32_t relay_count; -}; - - -/** - * Client context. - */ -struct Client { - struct GNUNET_SERVICE_Client *client; - struct Group *group; -}; - - -struct ReplayRequestKey -{ - uint64_t fragment_id; - uint64_t message_id; - uint64_t fragment_offset; - uint64_t flags; -}; - - -static struct Channel * -cadet_channel_create (struct Group *grp, struct GNUNET_PeerIdentity *peer); - -static void -cadet_channel_destroy (struct Channel *chn); - -static void -client_send_join_decision (struct Member *mem, - const struct MulticastJoinDecisionMessageHeader *hdcsn); - - -/** - * Task run during shutdown. - * - * @param cls unused - */ -static void -shutdown_task (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "shutting down\n"); - if (NULL != cadet) - { - GNUNET_CADET_disconnect (cadet); - cadet = NULL; - } - if (NULL != stats) - { - GNUNET_STATISTICS_destroy (stats, GNUNET_YES); - stats = NULL; - } - /* FIXME: do more clean up here */ -} - - -/** - * Clean up origin data structures after a client disconnected. - */ -static void -cleanup_origin (struct Origin *orig) -{ - struct Group *grp = &orig->group; - GNUNET_CONTAINER_multihashmap_remove (origins, &grp->pub_key_hash, orig); - if (NULL != orig->cadet_port) - { - GNUNET_CADET_close_port (orig->cadet_port); - orig->cadet_port = NULL; - } - GNUNET_free (orig); -} - - -/** - * Clean up member data structures after a client disconnected. - */ -static void -cleanup_member (struct Member *mem) -{ - struct Group *grp = &mem->group; - struct GNUNET_CONTAINER_MultiHashMap * - grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members, - &grp->pub_key_hash); - GNUNET_assert (NULL != grp_mem); - GNUNET_CONTAINER_multihashmap_remove (grp_mem, &mem->pub_key_hash, mem); - - if (0 == GNUNET_CONTAINER_multihashmap_size (grp_mem)) - { - GNUNET_CONTAINER_multihashmap_remove (group_members, &grp->pub_key_hash, - grp_mem); - GNUNET_CONTAINER_multihashmap_destroy (grp_mem); - } - if (NULL != mem->join_dcsn) - { - GNUNET_free (mem->join_dcsn); - mem->join_dcsn = NULL; - } - if (NULL != mem->origin_channel) - { - GNUNET_CADET_channel_destroy (mem->origin_channel->channel); - mem->origin_channel = NULL; - } - GNUNET_CONTAINER_multihashmap_remove (members, &grp->pub_key_hash, mem); - GNUNET_free (mem); -} - - -/** - * Clean up group data structures after a client disconnected. - */ -static void -cleanup_group (struct Group *grp) -{ - (GNUNET_YES == grp->is_origin) - ? cleanup_origin (grp->origin) - : cleanup_member (grp->member); -} - - -void -replay_key_hash (uint64_t fragment_id, uint64_t message_id, - uint64_t fragment_offset, uint64_t flags, - struct GNUNET_HashCode *key_hash) -{ - struct ReplayRequestKey key = { - .fragment_id = fragment_id, - .message_id = message_id, - .fragment_offset = fragment_offset, - .flags = flags, - }; - GNUNET_CRYPTO_hash (&key, sizeof (key), key_hash); -} - - -/** - * Remove channel from replay request hashmap. - * - * @param chn - * Channel to remove. - * - * @return #GNUNET_YES if there are more entries to process, - * #GNUNET_NO when reached end of hashmap. - */ -static int -replay_req_remove_cadet (struct Channel *chn) -{ - if (NULL == chn || NULL == chn->group) - return GNUNET_SYSERR; - - struct GNUNET_CONTAINER_MultiHashMap * - grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet, - &chn->group->pub_key_hash); - if (NULL == grp_replay_req) - return GNUNET_NO; - - struct GNUNET_CONTAINER_MultiHashMapIterator * - it = GNUNET_CONTAINER_multihashmap_iterator_create (grp_replay_req); - struct GNUNET_HashCode key; - const struct Channel *c; - while (GNUNET_YES - == GNUNET_CONTAINER_multihashmap_iterator_next (it, &key, - (const void **) &c)) - { - if (c == chn) - { - GNUNET_CONTAINER_multihashmap_remove (grp_replay_req, &key, chn); - GNUNET_CONTAINER_multihashmap_iterator_destroy (it); - return GNUNET_YES; - } - } - GNUNET_CONTAINER_multihashmap_iterator_destroy (it); - return GNUNET_NO; -} - - -/** - * Remove client from replay request hashmap. - * - * @param client - * Client to remove. - * - * @return #GNUNET_YES if there are more entries to process, - * #GNUNET_NO when reached end of hashmap. - */ -static int -replay_req_remove_client (struct Group *grp, struct GNUNET_SERVICE_Client *client) -{ - struct GNUNET_CONTAINER_MultiHashMap * - grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_client, - &grp->pub_key_hash); - if (NULL == grp_replay_req) - return GNUNET_NO; - - struct GNUNET_CONTAINER_MultiHashMapIterator * - it = GNUNET_CONTAINER_multihashmap_iterator_create (grp_replay_req); - struct GNUNET_HashCode key; - const struct GNUNET_SERVICE_Client *c; - while (GNUNET_YES - == GNUNET_CONTAINER_multihashmap_iterator_next (it, &key, - (const void **) &c)) - { - if (c == client) - { - GNUNET_CONTAINER_multihashmap_remove (grp_replay_req, &key, client); - GNUNET_CONTAINER_multihashmap_iterator_destroy (it); - return GNUNET_YES; - } - } - GNUNET_CONTAINER_multihashmap_iterator_destroy (it); - return GNUNET_NO; -} - - -/** - * Send message to a client. - */ -static void -client_send (struct GNUNET_SERVICE_Client *client, - const struct GNUNET_MessageHeader *msg) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "%p Sending message to client.\n", client); - - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_copy (msg); - - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), - env); -} - - -/** - * Send message to all clients connected to the group. - */ -static void -client_send_group_keep_envelope (const struct Group *grp, - struct GNUNET_MQ_Envelope *env) -{ - struct ClientList *cli = grp->clients_head; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "%p Sending message to all clients of the group.\n", - grp); - while (NULL != cli) - { - GNUNET_MQ_send_copy (GNUNET_SERVICE_client_get_mq (cli->client), - env); - cli = cli->next; - } -} - - -/** - * Send message to all clients connected to the group and - * takes care of freeing @env. - */ -static void -client_send_group (const struct Group *grp, - struct GNUNET_MQ_Envelope *env) -{ - client_send_group_keep_envelope (grp, env); - GNUNET_MQ_discard (env); -} - - -/** - * Iterator callback for sending a message to origin clients. - */ -static int -client_send_origin_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash, - void *origin) -{ - struct GNUNET_MQ_Envelope *env = cls; - struct Member *orig = origin; - - client_send_group_keep_envelope (&orig->group, env); - return GNUNET_YES; -} - - -/** - * Iterator callback for sending a message to member clients. - */ -static int -client_send_member_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash, - void *member) -{ - struct GNUNET_MQ_Envelope *env = cls; - struct Member *mem = member; - - if (NULL != mem->join_dcsn) - { /* Only send message to admitted members */ - client_send_group_keep_envelope (&mem->group, env); - } - return GNUNET_YES; -} - - -/** - * Send message to all origin and member clients connected to the group. - * - * @param pub_key_hash - * H(key_pub) of the group. - * @param msg - * Message to send. - */ -static int -client_send_all (struct GNUNET_HashCode *pub_key_hash, - struct GNUNET_MQ_Envelope *env) -{ - int n = 0; - n += GNUNET_CONTAINER_multihashmap_get_multiple (origins, pub_key_hash, - client_send_origin_cb, - (void *) env); - n += GNUNET_CONTAINER_multihashmap_get_multiple (members, pub_key_hash, - client_send_member_cb, - (void *) env); - GNUNET_MQ_discard (env); - return n; -} - - -/** - * Send message to a random origin client or a random member client. - * - * @param grp The group to send @a msg to. - * @param msg Message to send. - */ -static int -client_send_random (struct GNUNET_HashCode *pub_key_hash, - struct GNUNET_MQ_Envelope *env) -{ - int n = 0; - n = GNUNET_CONTAINER_multihashmap_get_random (origins, client_send_origin_cb, - (void *) env); - if (n <= 0) - n = GNUNET_CONTAINER_multihashmap_get_random (members, client_send_member_cb, - (void *) env); - GNUNET_MQ_discard (env); - return n; -} - - -/** - * Send message to all origin clients connected to the group. - * - * @param pub_key_hash - * H(key_pub) of the group. - * @param msg - * Message to send. - */ -static int -client_send_origin (struct GNUNET_HashCode *pub_key_hash, - struct GNUNET_MQ_Envelope *env) -{ - int n = 0; - n += GNUNET_CONTAINER_multihashmap_get_multiple (origins, pub_key_hash, - client_send_origin_cb, - (void *) env); - return n; -} - - -/** - * Send fragment acknowledgement to all clients of the channel. - * - * @param pub_key_hash - * H(key_pub) of the group. - */ -static void -client_send_ack (struct GNUNET_HashCode *pub_key_hash) -{ - struct GNUNET_MQ_Envelope *env; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Sending message ACK to client.\n"); - env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_FRAGMENT_ACK); - client_send_all (pub_key_hash, env); -} - - -struct CadetTransmitClosure -{ - struct Channel *chn; - const struct GNUNET_MessageHeader *msg; -}; - - -/** - * Send a message to a CADET channel. - * - * @param chn Channel. - * @param msg Message. - */ -static void -cadet_send_channel (struct Channel *chn, const struct GNUNET_MessageHeader *msg) -{ - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_copy (msg); - - GNUNET_MQ_send (GNUNET_CADET_get_mq (chn->channel), env); - - if (0 < chn->window_size) - { - client_send_ack (&chn->group_pub_hash); - } - else - { - chn->msgs_pending++; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "%p Queuing message. Pending messages: %u\n", - chn, chn->msgs_pending); - } -} - - -/** - * Create CADET channel and send a join request. - */ -static void -cadet_send_join_request (struct Member *mem) -{ - mem->origin_channel = cadet_channel_create (&mem->group, &mem->origin); - cadet_send_channel (mem->origin_channel, &mem->join_req->header); - - uint32_t i; - for (i = 0; i < mem->relay_count; i++) - { - struct Channel * - chn = cadet_channel_create (&mem->group, &mem->relays[i]); - cadet_send_channel (chn, &mem->join_req->header); - } -} - - -static int -cadet_send_join_decision_cb (void *cls, - const struct GNUNET_HashCode *group_pub_hash, - void *channel) -{ - const struct MulticastJoinDecisionMessageHeader *hdcsn = cls; - struct Channel *chn = channel; - - const struct MulticastJoinDecisionMessage *dcsn = - (struct MulticastJoinDecisionMessage *) &hdcsn[1]; - - if (0 == memcmp (&hdcsn->member_pub_key, &chn->member_pub_key, sizeof (chn->member_pub_key)) - && 0 == memcmp (&hdcsn->peer, &chn->peer, sizeof (chn->peer))) - { - if (GNUNET_YES == ntohl (dcsn->is_admitted)) - { - chn->join_status = JOIN_ADMITTED; - } - else - { - chn->join_status = JOIN_REFUSED; - } - cadet_send_channel (chn, &hdcsn->header); - return GNUNET_YES; - } - - // return GNUNET_YES to continue the multihashmap_get iteration - return GNUNET_YES; -} - - -/** - * Send join decision to a remote peer. - */ -static void -cadet_send_join_decision (struct Group *grp, - const struct MulticastJoinDecisionMessageHeader *hdcsn) -{ - GNUNET_CONTAINER_multihashmap_get_multiple (channels_in, &grp->pub_key_hash, - &cadet_send_join_decision_cb, - (void *) hdcsn); -} - - -/** - * Iterator callback for sending a message to origin clients. - */ -static int -cadet_send_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash, - void *channel) -{ - const struct GNUNET_MessageHeader *msg = cls; - struct Channel *chn = channel; - if (JOIN_ADMITTED == chn->join_status) - cadet_send_channel (chn, msg); - return GNUNET_YES; -} - - -/** - * Send message to all connected children. - */ -static int -cadet_send_children (struct GNUNET_HashCode *pub_key_hash, - const struct GNUNET_MessageHeader *msg) -{ - int n = 0; - if (channels_in != NULL) - n += GNUNET_CONTAINER_multihashmap_get_multiple (channels_in, pub_key_hash, - cadet_send_cb, (void *) msg); - return n; -} - - -#if 0 // unused as yet -/** - * Send message to all connected parents. - */ -static int -cadet_send_parents (struct GNUNET_HashCode *pub_key_hash, - const struct GNUNET_MessageHeader *msg) -{ - int n = 0; - if (channels_in != NULL) - n += GNUNET_CONTAINER_multihashmap_get_multiple (channels_out, pub_key_hash, - cadet_send_cb, (void *) msg); - return n; -} -#endif - - -/** - * CADET channel connect handler. - * - * @see GNUNET_CADET_ConnectEventHandler() - */ -static void * -cadet_notify_connect (void *cls, - struct GNUNET_CADET_Channel *channel, - const struct GNUNET_PeerIdentity *source) -{ - struct Channel *chn = GNUNET_malloc (sizeof (struct Channel)); - chn->group = cls; - chn->channel = channel; - chn->direction = DIR_INCOMING; - chn->join_status = JOIN_NOT_ASKED; - - GNUNET_CONTAINER_multihashmap_put (channels_in, &chn->group->pub_key_hash, chn, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - return chn; -} - - -/** - * CADET window size change handler. - * - * @see GNUNET_CADET_WindowSizeEventHandler() - */ -static void -cadet_notify_window_change (void *cls, - const struct GNUNET_CADET_Channel *channel, - int window_size) -{ - struct Channel *chn = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "%p Window size changed to %d. Pending messages: %u\n", - chn, window_size, chn->msgs_pending); - - chn->is_connected = GNUNET_YES; - chn->window_size = (int32_t) window_size; - - for (int i = 0; i < window_size; i++) - { - if (0 < chn->msgs_pending) - { - client_send_ack (&chn->group_pub_hash); - chn->msgs_pending--; - } - else - { - break; - } - } -} - - -/** - * CADET channel disconnect handler. - * - * @see GNUNET_CADET_DisconnectEventHandler() - */ -static void -cadet_notify_disconnect (void *cls, - const struct GNUNET_CADET_Channel *channel) -{ - if (NULL == cls) - return; - - struct Channel *chn = cls; - if (NULL != chn->group) - { - if (GNUNET_NO == chn->group->is_origin) - { - struct Member *mem = (struct Member *) chn->group; - if (chn == mem->origin_channel) - mem->origin_channel = NULL; - } - } - - int ret; - do - { - ret = replay_req_remove_cadet (chn); - } - while (GNUNET_YES == ret); - - GNUNET_free (chn); -} - - -static int -check_cadet_join_request (void *cls, - const struct MulticastJoinRequestMessage *req) -{ - struct Channel *chn = cls; - - if (NULL == chn - || JOIN_NOT_ASKED != chn->join_status) - { - return GNUNET_SYSERR; - } - - uint16_t size = ntohs (req->header.size); - if (size < sizeof (*req)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (ntohl (req->purpose.size) != (size - - sizeof (req->header) - - sizeof (req->reserved) - - sizeof (req->signature))) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST, - &req->purpose, &req->signature, - &req->member_pub_key)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - return GNUNET_OK; -} - - -/** - * Incoming join request message from CADET. - */ -static void -handle_cadet_join_request (void *cls, - const struct MulticastJoinRequestMessage *req) -{ - struct Channel *chn = cls; - GNUNET_CADET_receive_done (chn->channel); - - struct GNUNET_HashCode group_pub_hash; - GNUNET_CRYPTO_hash (&req->group_pub_key, sizeof (req->group_pub_key), &group_pub_hash); - chn->group_pub_key = req->group_pub_key; - chn->group_pub_hash = group_pub_hash; - chn->member_pub_key = req->member_pub_key; - chn->peer = req->peer; - chn->join_status = JOIN_WAITING; - - client_send_all (&group_pub_hash, - GNUNET_MQ_msg_copy (&req->header)); -} - - -static int -check_cadet_join_decision (void *cls, - const struct MulticastJoinDecisionMessageHeader *hdcsn) -{ - uint16_t size = ntohs (hdcsn->header.size); - if (size < sizeof (struct MulticastJoinDecisionMessageHeader) + - sizeof (struct MulticastJoinDecisionMessage)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - struct Channel *chn = cls; - if (NULL == chn) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (NULL == chn->group || GNUNET_NO != chn->group->is_origin) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - switch (chn->join_status) - { - case JOIN_REFUSED: - return GNUNET_SYSERR; - - case JOIN_ADMITTED: - return GNUNET_OK; - - case JOIN_NOT_ASKED: - case JOIN_WAITING: - break; - } - - return GNUNET_OK; -} - - -/** - * Incoming join decision message from CADET. - */ -static void -handle_cadet_join_decision (void *cls, - const struct MulticastJoinDecisionMessageHeader *hdcsn) -{ - const struct MulticastJoinDecisionMessage * - dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1]; - - struct Channel *chn = cls; - GNUNET_CADET_receive_done (chn->channel); - - // FIXME: do we need to copy chn->peer or compare it with hdcsn->peer? - struct Member *mem = (struct Member *) chn->group; - client_send_join_decision (mem, hdcsn); - if (GNUNET_YES == ntohl (dcsn->is_admitted)) - { - chn->join_status = JOIN_ADMITTED; - } - else - { - chn->join_status = JOIN_REFUSED; - cadet_channel_destroy (chn); - } -} - - -static int -check_cadet_message (void *cls, - const struct GNUNET_MULTICAST_MessageHeader *msg) -{ - uint16_t size = ntohs (msg->header.size); - if (size < sizeof (*msg)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - struct Channel *chn = cls; - if (NULL == chn) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (ntohl (msg->purpose.size) != (size - - sizeof (msg->header) - - sizeof (msg->hop_counter) - - sizeof (msg->signature))) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE, - &msg->purpose, &msg->signature, - &chn->group_pub_key)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - return GNUNET_OK; -} - - -/** - * Incoming multicast message from CADET. - */ -static void -handle_cadet_message (void *cls, - const struct GNUNET_MULTICAST_MessageHeader *msg) -{ - struct Channel *chn = cls; - GNUNET_CADET_receive_done (chn->channel); - client_send_all (&chn->group_pub_hash, - GNUNET_MQ_msg_copy (&msg->header)); -} - - -static int -check_cadet_request (void *cls, - const struct GNUNET_MULTICAST_RequestHeader *req) -{ - uint16_t size = ntohs (req->header.size); - if (size < sizeof (*req)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - struct Channel *chn = cls; - if (NULL == chn) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (ntohl (req->purpose.size) != (size - - sizeof (req->header) - - sizeof (req->member_pub_key) - - sizeof (req->signature))) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST, - &req->purpose, &req->signature, - &req->member_pub_key)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - return GNUNET_OK; -} - - -/** - * Incoming multicast request message from CADET. - */ -static void -handle_cadet_request (void *cls, - const struct GNUNET_MULTICAST_RequestHeader *req) -{ - struct Channel *chn = cls; - GNUNET_CADET_receive_done (chn->channel); - client_send_origin (&chn->group_pub_hash, - GNUNET_MQ_msg_copy (&req->header)); -} - - -// FIXME: do checks in handle_cadet_replay_request -//static int -//check_cadet_replay_request (void *cls, -// const struct MulticastReplayRequestMessage *req) -//{ -// uint16_t size = ntohs (req->header.size); -// if (size < sizeof (*req)) -// { -// GNUNET_break_op (0); -// return GNUNET_SYSERR; -// } -// -// struct Channel *chn = cls; -// if (NULL == chn) -// { -// GNUNET_break_op (0); -// return GNUNET_SYSERR; -// } -// -// return GNUNET_OK; -//} - - -/** - * Incoming multicast replay request from CADET. - */ -static void -handle_cadet_replay_request (void *cls, - const struct MulticastReplayRequestMessage *req) -{ - struct Channel *chn = cls; - - GNUNET_CADET_receive_done (chn->channel); - - struct MulticastReplayRequestMessage rep = *req; - GNUNET_memcpy (&rep.member_pub_key, &chn->member_pub_key, sizeof (chn->member_pub_key)); - - struct GNUNET_CONTAINER_MultiHashMap * - grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet, - &chn->group->pub_key_hash); - if (NULL == grp_replay_req) - { - grp_replay_req = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - GNUNET_CONTAINER_multihashmap_put (replay_req_cadet, - &chn->group->pub_key_hash, grp_replay_req, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - } - struct GNUNET_HashCode key_hash; - replay_key_hash (rep.fragment_id, - rep.message_id, - rep.fragment_offset, - rep.flags, - &key_hash); - GNUNET_CONTAINER_multihashmap_put (grp_replay_req, &key_hash, chn, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - - client_send_random (&chn->group_pub_hash, - GNUNET_MQ_msg_copy (&rep.header)); -} - - -static int -check_cadet_replay_response (void *cls, - const struct MulticastReplayResponseMessage *res) -{ - struct Channel *chn = cls; - if (NULL == chn) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Incoming multicast replay response from CADET. - */ -static void -handle_cadet_replay_response (void *cls, - const struct MulticastReplayResponseMessage *res) -{ - struct Channel *chn = cls; - GNUNET_CADET_receive_done (chn->channel); - - /* @todo FIXME: got replay error response, send request to other members */ -} - - -static void -group_set_cadet_port_hash (struct Group *grp) -{ - struct CadetPort { - struct GNUNET_CRYPTO_EddsaPublicKey pub_key; - uint32_t app_type; - } port = { - grp->pub_key, - GNUNET_APPLICATION_TYPE_MULTICAST, - }; - GNUNET_CRYPTO_hash (&port, sizeof (port), &grp->cadet_port_hash); -} - - - -/** - * Create new outgoing CADET channel. - * - * @param peer - * Peer to connect to. - * @param group_pub_key - * Public key of group the channel belongs to. - * @param group_pub_hash - * Hash of @a group_pub_key. - * - * @return Channel. - */ -static struct Channel * -cadet_channel_create (struct Group *grp, struct GNUNET_PeerIdentity *peer) -{ - struct Channel *chn = GNUNET_malloc (sizeof (*chn)); - chn->group = grp; - chn->group_pub_key = grp->pub_key; - chn->group_pub_hash = grp->pub_key_hash; - chn->peer = *peer; - chn->direction = DIR_OUTGOING; - chn->is_connected = GNUNET_NO; - chn->join_status = JOIN_WAITING; - - struct GNUNET_MQ_MessageHandler cadet_handlers[] = { - GNUNET_MQ_hd_var_size (cadet_message, - GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE, - struct GNUNET_MULTICAST_MessageHeader, - chn), - - GNUNET_MQ_hd_var_size (cadet_join_decision, - GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION, - struct MulticastJoinDecisionMessageHeader, - chn), - - GNUNET_MQ_hd_fixed_size (cadet_replay_request, - GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST, - struct MulticastReplayRequestMessage, - chn), - - GNUNET_MQ_hd_var_size (cadet_replay_response, - GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE, - struct MulticastReplayResponseMessage, - chn), - - GNUNET_MQ_handler_end () - }; - - chn->channel = GNUNET_CADET_channel_create (cadet, chn, &chn->peer, - &grp->cadet_port_hash, - GNUNET_CADET_OPTION_RELIABLE, - cadet_notify_window_change, - cadet_notify_disconnect, - cadet_handlers); - GNUNET_CONTAINER_multihashmap_put (channels_out, &chn->group_pub_hash, chn, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - return chn; -} - - -/** - * Destroy outgoing CADET channel. - */ -static void -cadet_channel_destroy (struct Channel *chn) -{ - GNUNET_CADET_channel_destroy (chn->channel); - GNUNET_CONTAINER_multihashmap_remove_all (channels_out, &chn->group_pub_hash); - GNUNET_free (chn); -} - -/** - * Handle a connecting client starting an origin. - */ -static void -handle_client_origin_start (void *cls, - const struct MulticastOriginStartMessage *msg) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - - struct GNUNET_CRYPTO_EddsaPublicKey pub_key; - struct GNUNET_HashCode pub_key_hash; - - GNUNET_CRYPTO_eddsa_key_get_public (&msg->group_key, &pub_key); - GNUNET_CRYPTO_hash (&pub_key, sizeof (pub_key), &pub_key_hash); - - struct Origin * - orig = GNUNET_CONTAINER_multihashmap_get (origins, &pub_key_hash); - struct Group *grp; - - if (NULL == orig) - { - orig = GNUNET_new (struct Origin); - orig->priv_key = msg->group_key; - orig->max_fragment_id = GNUNET_ntohll (msg->max_fragment_id); - - grp = c->group = &orig->group; - grp->origin = orig; - grp->is_origin = GNUNET_YES; - grp->pub_key = pub_key; - grp->pub_key_hash = pub_key_hash; - grp->is_disconnected = GNUNET_NO; - - GNUNET_CONTAINER_multihashmap_put (origins, &grp->pub_key_hash, orig, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - - group_set_cadet_port_hash (grp); - - struct GNUNET_MQ_MessageHandler cadet_handlers[] = { - GNUNET_MQ_hd_var_size (cadet_message, - GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE, - struct GNUNET_MULTICAST_MessageHeader, - grp), - - GNUNET_MQ_hd_var_size (cadet_request, - GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST, - struct GNUNET_MULTICAST_RequestHeader, - grp), - - GNUNET_MQ_hd_var_size (cadet_join_request, - GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST, - struct MulticastJoinRequestMessage, - grp), - - GNUNET_MQ_hd_fixed_size (cadet_replay_request, - GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST, - struct MulticastReplayRequestMessage, - grp), - - GNUNET_MQ_hd_var_size (cadet_replay_response, - GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE, - struct MulticastReplayResponseMessage, - grp), - - GNUNET_MQ_handler_end () - }; - - - orig->cadet_port = GNUNET_CADET_open_port (cadet, - &grp->cadet_port_hash, - cadet_notify_connect, - grp, - cadet_notify_window_change, - cadet_notify_disconnect, - cadet_handlers); - } - else - { - grp = &orig->group; - } - - struct ClientList *cl = GNUNET_new (struct ClientList); - cl->client = client; - GNUNET_CONTAINER_DLL_insert (grp->clients_head, grp->clients_tail, cl); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Client connected as origin to group %s.\n", - orig, GNUNET_h2s (&grp->pub_key_hash)); - GNUNET_SERVICE_client_continue (client); -} - - -static int -check_client_member_join (void *cls, - const struct MulticastMemberJoinMessage *msg) -{ - uint16_t msg_size = ntohs (msg->header.size); - struct GNUNET_PeerIdentity *relays = (struct GNUNET_PeerIdentity *) &msg[1]; - uint32_t relay_count = ntohl (msg->relay_count); - - if (0 != relay_count) - { - if (UINT32_MAX / relay_count < sizeof (*relays)){ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "relay_count (%lu) * sizeof (*relays) (%lu) exceeds UINT32_MAX!\n", - (unsigned long)relay_count, - sizeof (*relays)); - return GNUNET_SYSERR; - } - } - uint32_t relay_size = relay_count * sizeof (*relays); - struct GNUNET_MessageHeader *join_msg = NULL; - uint16_t join_msg_size = 0; - if (sizeof (*msg) + relay_size + sizeof (struct GNUNET_MessageHeader) - <= msg_size) - { - join_msg = (struct GNUNET_MessageHeader *) - (((char *) &msg[1]) + relay_size); - join_msg_size = ntohs (join_msg->size); - if (UINT16_MAX - join_msg_size < sizeof (struct MulticastJoinRequestMessage)){ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "join_msg_size (%u) + sizeof (struct MulticastJoinRequestMessage) (%lu) exceeds UINT16_MAX!\n", - (unsigned)join_msg_size, - (unsigned long)sizeof (struct MulticastJoinRequestMessage)); - return GNUNET_SYSERR; - } - } - if (msg_size != (sizeof (*msg) + relay_size + join_msg_size)){ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "msg_size does not match real size of message!\n"); - return GNUNET_SYSERR; - }else{ - return GNUNET_OK; - } -} - - -/** - * Handle a connecting client joining a group. - */ -static void -handle_client_member_join (void *cls, - const struct MulticastMemberJoinMessage *msg) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - - uint16_t msg_size = ntohs (msg->header.size); - - struct GNUNET_CRYPTO_EcdsaPublicKey mem_pub_key; - struct GNUNET_HashCode pub_key_hash, mem_pub_key_hash; - - GNUNET_CRYPTO_ecdsa_key_get_public (&msg->member_key, &mem_pub_key); - GNUNET_CRYPTO_hash (&mem_pub_key, sizeof (mem_pub_key), &mem_pub_key_hash); - GNUNET_CRYPTO_hash (&msg->group_pub_key, sizeof (msg->group_pub_key), &pub_key_hash); - - struct GNUNET_CONTAINER_MultiHashMap * - grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members, &pub_key_hash); - struct Member *mem = NULL; - struct Group *grp; - - if (NULL != grp_mem) - { - mem = GNUNET_CONTAINER_multihashmap_get (grp_mem, &mem_pub_key_hash); - } - - if (NULL == mem) - { - mem = GNUNET_new (struct Member); - mem->origin = msg->origin; - mem->priv_key = msg->member_key; - mem->pub_key = mem_pub_key; - mem->pub_key_hash = mem_pub_key_hash; - mem->max_fragment_id = 0; // FIXME - - grp = c->group = &mem->group; - grp->member = mem; - grp->is_origin = GNUNET_NO; - grp->pub_key = msg->group_pub_key; - grp->pub_key_hash = pub_key_hash; - grp->is_disconnected = GNUNET_NO; - group_set_cadet_port_hash (grp); - - if (NULL == grp_mem) - { - grp_mem = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); - GNUNET_CONTAINER_multihashmap_put (group_members, &grp->pub_key_hash, grp_mem, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - } - GNUNET_CONTAINER_multihashmap_put (grp_mem, &mem->pub_key_hash, mem, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - - // FIXME: should the members hash map have option UNIQUE_FAST? - GNUNET_CONTAINER_multihashmap_put (members, &grp->pub_key_hash, mem, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - } - else - { - grp = &mem->group; - } - - struct ClientList *cl = GNUNET_new (struct ClientList); - cl->client = client; - GNUNET_CONTAINER_DLL_insert (grp->clients_head, grp->clients_tail, cl); - - char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&mem->pub_key); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Client connected to group %s as member %s (%s). size = %d\n", - GNUNET_h2s (&grp->pub_key_hash), - GNUNET_h2s2 (&mem->pub_key_hash), - str, - GNUNET_CONTAINER_multihashmap_size (members)); - GNUNET_free (str); - - if (NULL != mem->join_dcsn) - { /* Already got a join decision, send it to client. */ - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_copy (&mem->join_dcsn->header); - - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), - env); - } - else - { /* First client of the group, send join request. */ - struct GNUNET_PeerIdentity *relays = (struct GNUNET_PeerIdentity *) &msg[1]; - uint32_t relay_count = ntohl (msg->relay_count); - uint16_t relay_size = relay_count * sizeof (*relays); - struct GNUNET_MessageHeader *join_msg = NULL; - uint16_t join_msg_size = 0; - if (sizeof (*msg) + relay_size + sizeof (struct GNUNET_MessageHeader) - <= msg_size) - { - join_msg = (struct GNUNET_MessageHeader *) - (((char *) &msg[1]) + relay_size); - join_msg_size = ntohs (join_msg->size); - } - - uint16_t req_msg_size = sizeof (struct MulticastJoinRequestMessage) + join_msg_size; - struct MulticastJoinRequestMessage * - req = GNUNET_malloc (req_msg_size); - req->header.size = htons (req_msg_size); - req->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST); - req->group_pub_key = grp->pub_key; - req->peer = this_peer; - GNUNET_CRYPTO_ecdsa_key_get_public (&mem->priv_key, &req->member_pub_key); - if (0 < join_msg_size) - GNUNET_memcpy (&req[1], join_msg, join_msg_size); - - req->member_pub_key = mem->pub_key; - req->purpose.size = htonl (req_msg_size - - sizeof (req->header) - - sizeof (req->reserved) - - sizeof (req->signature)); - req->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST); - - if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (&mem->priv_key, &req->purpose, - &req->signature)) - { - /* FIXME: handle error */ - GNUNET_assert (0); - } - - if (NULL != mem->join_req) - GNUNET_free (mem->join_req); - mem->join_req = req; - - if (0 == - client_send_origin (&grp->pub_key_hash, - GNUNET_MQ_msg_copy (&mem->join_req->header))) - { /* No local origins, send to remote origin */ - cadet_send_join_request (mem); - } - } - GNUNET_SERVICE_client_continue (client); -} - - -static void -client_send_join_decision (struct Member *mem, - const struct MulticastJoinDecisionMessageHeader *hdcsn) -{ - client_send_group (&mem->group, GNUNET_MQ_msg_copy (&hdcsn->header)); - - const struct MulticastJoinDecisionMessage * - dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1]; - if (GNUNET_YES == ntohl (dcsn->is_admitted)) - { /* Member admitted, store join_decision. */ - uint16_t dcsn_size = ntohs (dcsn->header.size); - mem->join_dcsn = GNUNET_malloc (dcsn_size); - GNUNET_memcpy (mem->join_dcsn, dcsn, dcsn_size); - } - else - { /* Refused entry, but replay would be still possible for past members. */ - } -} - - -static int -check_client_join_decision (void *cls, - const struct MulticastJoinDecisionMessageHeader *hdcsn) -{ - return GNUNET_OK; -} - - -/** - * Join decision from client. - */ -static void -handle_client_join_decision (void *cls, - const struct MulticastJoinDecisionMessageHeader *hdcsn) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - struct Group *grp = c->group; - - if (NULL == grp) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - GNUNET_assert (GNUNET_NO == grp->is_disconnected); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p got join decision from client for group %s..\n", - grp, GNUNET_h2s (&grp->pub_key_hash)); - - struct GNUNET_CONTAINER_MultiHashMap * - grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members, - &grp->pub_key_hash); - struct Member *mem = NULL; - if (NULL != grp_mem) - { - struct GNUNET_HashCode member_key_hash; - GNUNET_CRYPTO_hash (&hdcsn->member_pub_key, sizeof (hdcsn->member_pub_key), - &member_key_hash); - mem = GNUNET_CONTAINER_multihashmap_get (grp_mem, &member_key_hash); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p ..and member %s: %p\n", - grp, GNUNET_h2s (&member_key_hash), mem); - } - - if (NULL != mem) - { /* Found local member */ - client_send_join_decision (mem, hdcsn); - } - else - { /* Look for remote member */ - cadet_send_join_decision (grp, hdcsn); - } - GNUNET_SERVICE_client_continue (client); -} - - -static void -handle_client_part_request (void *cls, - const struct GNUNET_MessageHeader *msg) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - struct Group *grp = c->group; - struct GNUNET_MQ_Envelope *env; - - if (NULL == grp) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - GNUNET_assert (GNUNET_NO == grp->is_disconnected); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p got part request from client for group %s.\n", - grp, GNUNET_h2s (&grp->pub_key_hash)); - grp->is_disconnected = GNUNET_YES; - env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_PART_ACK); - client_send_group (grp, env); - GNUNET_SERVICE_client_continue (client); -} - - -static int -check_client_multicast_message (void *cls, - const struct GNUNET_MULTICAST_MessageHeader *msg) -{ - return GNUNET_OK; -} - - -/** - * Incoming message from a client. - */ -static void -handle_client_multicast_message (void *cls, - const struct GNUNET_MULTICAST_MessageHeader *msg) -{ - // FIXME: what if GNUNET_YES == grp->is_disconnected? Do we allow sending messages? - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - struct Group *grp = c->group; - - if (NULL == grp) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - GNUNET_assert (GNUNET_YES == grp->is_origin); - struct Origin *orig = grp->origin; - - // FIXME: use GNUNET_MQ_msg_copy - /* FIXME: yucky, should use separate message structs for P2P and CS! */ - struct GNUNET_MULTICAST_MessageHeader * - out = (struct GNUNET_MULTICAST_MessageHeader *) GNUNET_copy_message (&msg->header); - out->fragment_id = GNUNET_htonll (++orig->max_fragment_id); - out->purpose.size = htonl (ntohs (out->header.size) - - sizeof (out->header) - - sizeof (out->hop_counter) - - sizeof (out->signature)); - out->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE); - - if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign (&orig->priv_key, &out->purpose, - &out->signature)) - { - GNUNET_assert (0); - } - - client_send_all (&grp->pub_key_hash, GNUNET_MQ_msg_copy (&out->header)); - cadet_send_children (&grp->pub_key_hash, &out->header); - client_send_ack (&grp->pub_key_hash); - GNUNET_free (out); - - GNUNET_SERVICE_client_continue (client); -} - - -static int -check_client_multicast_request (void *cls, - const struct GNUNET_MULTICAST_RequestHeader *req) -{ - return GNUNET_OK; -} - - -/** - * Incoming request from a client. - */ -static void -handle_client_multicast_request (void *cls, - const struct GNUNET_MULTICAST_RequestHeader *req) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - struct Group *grp = c->group; - - if (NULL == grp) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - GNUNET_assert (GNUNET_NO == grp->is_disconnected); - GNUNET_assert (GNUNET_NO == grp->is_origin); - struct Member *mem = grp->member; - - /* FIXME: yucky, should use separate message structs for P2P and CS! */ - struct GNUNET_MULTICAST_RequestHeader * - out = (struct GNUNET_MULTICAST_RequestHeader *) GNUNET_copy_message (&req->header); - out->member_pub_key = mem->pub_key; - out->fragment_id = GNUNET_ntohll (++mem->max_fragment_id); - out->purpose.size = htonl (ntohs (out->header.size) - - sizeof (out->header) - - sizeof (out->member_pub_key) - - sizeof (out->signature)); - out->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST); - - if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (&mem->priv_key, &out->purpose, - &out->signature)) - { - GNUNET_assert (0); - } - - uint8_t send_ack = GNUNET_YES; - if (0 == - client_send_origin (&grp->pub_key_hash, - GNUNET_MQ_msg_copy (&out->header))) - { /* No local origins, send to remote origin */ - if (NULL != mem->origin_channel) - { - cadet_send_channel (mem->origin_channel, &out->header); - send_ack = GNUNET_NO; - } - else - { - /* FIXME: not yet connected to origin */ - GNUNET_SERVICE_client_drop (client); - GNUNET_free (out); - return; - } - } - if (GNUNET_YES == send_ack) - { - client_send_ack (&grp->pub_key_hash); - } - GNUNET_free (out); - GNUNET_SERVICE_client_continue (client); -} - - -/** - * Incoming replay request from a client. - */ -static void -handle_client_replay_request (void *cls, - const struct MulticastReplayRequestMessage *rep) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - struct Group *grp = c->group; - - if (NULL == grp) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - GNUNET_assert (GNUNET_NO == grp->is_disconnected); - GNUNET_assert (GNUNET_NO == grp->is_origin); - struct Member *mem = grp->member; - - struct GNUNET_CONTAINER_MultiHashMap * - grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_client, - &grp->pub_key_hash); - if (NULL == grp_replay_req) - { - grp_replay_req = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - GNUNET_CONTAINER_multihashmap_put (replay_req_client, - &grp->pub_key_hash, grp_replay_req, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - } - - struct GNUNET_HashCode key_hash; - replay_key_hash (rep->fragment_id, rep->message_id, rep->fragment_offset, - rep->flags, &key_hash); - GNUNET_CONTAINER_multihashmap_put (grp_replay_req, &key_hash, client, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - - if (0 == - client_send_origin (&grp->pub_key_hash, - GNUNET_MQ_msg_copy (&rep->header))) - { /* No local origin, replay from remote members / origin. */ - if (NULL != mem->origin_channel) - { - cadet_send_channel (mem->origin_channel, &rep->header); - } - else - { - /* FIXME: not yet connected to origin */ - - GNUNET_assert (0); - GNUNET_SERVICE_client_drop (client); - return; - } - } - GNUNET_SERVICE_client_continue (client); -} - - -static int -cadet_send_replay_response_cb (void *cls, - const struct GNUNET_HashCode *key_hash, - void *value) -{ - struct Channel *chn = value; - struct GNUNET_MessageHeader *msg = cls; - - cadet_send_channel (chn, msg); - return GNUNET_OK; -} - - -static int -client_send_replay_response_cb (void *cls, - const struct GNUNET_HashCode *key_hash, - void *value) -{ - struct GNUNET_SERVICE_Client *client = value; - struct GNUNET_MessageHeader *msg = cls; - - client_send (client, msg); - return GNUNET_OK; -} - - -static int -check_client_replay_response_end (void *cls, - const struct MulticastReplayResponseMessage *res) -{ - return GNUNET_OK; -} - - -/** - * End of replay response from a client. - */ -static void -handle_client_replay_response_end (void *cls, - const struct MulticastReplayResponseMessage *res) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - struct Group *grp = c->group; - - if (NULL == grp) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - GNUNET_assert (GNUNET_NO == grp->is_disconnected); - - struct GNUNET_HashCode key_hash; - replay_key_hash (res->fragment_id, res->message_id, res->fragment_offset, - res->flags, &key_hash); - - struct GNUNET_CONTAINER_MultiHashMap * - grp_replay_req_cadet = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet, - &grp->pub_key_hash); - if (NULL != grp_replay_req_cadet) - { - GNUNET_CONTAINER_multihashmap_remove_all (grp_replay_req_cadet, &key_hash); - } - struct GNUNET_CONTAINER_MultiHashMap * - grp_replay_req_client = GNUNET_CONTAINER_multihashmap_get (replay_req_client, - &grp->pub_key_hash); - if (NULL != grp_replay_req_client) - { - GNUNET_CONTAINER_multihashmap_remove_all (grp_replay_req_client, &key_hash); - } - GNUNET_SERVICE_client_continue (client); -} - - -static int -check_client_replay_response (void *cls, - const struct MulticastReplayResponseMessage *res) -{ - const struct GNUNET_MessageHeader *msg; - if (GNUNET_MULTICAST_REC_OK == res->error_code) - { - msg = GNUNET_MQ_extract_nested_mh (res); - if (NULL == msg) - { - return GNUNET_SYSERR; - } - } - return GNUNET_OK; -} - - -/** - * Incoming replay response from a client. - * - * Respond with a multicast message on success, or otherwise with an error code. - */ -static void -handle_client_replay_response (void *cls, - const struct MulticastReplayResponseMessage *res) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - struct Group *grp = c->group; - - if (NULL == grp) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - GNUNET_assert (GNUNET_NO == grp->is_disconnected); - - const struct GNUNET_MessageHeader *msg = &res->header; - if (GNUNET_MULTICAST_REC_OK == res->error_code) - { - msg = GNUNET_MQ_extract_nested_mh (res); - } - - struct GNUNET_HashCode key_hash; - replay_key_hash (res->fragment_id, res->message_id, res->fragment_offset, - res->flags, &key_hash); - - struct GNUNET_CONTAINER_MultiHashMap * - grp_replay_req_cadet = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet, - &grp->pub_key_hash); - if (NULL != grp_replay_req_cadet) - { - GNUNET_CONTAINER_multihashmap_get_multiple (grp_replay_req_cadet, &key_hash, - cadet_send_replay_response_cb, - (void *) msg); - } - if (GNUNET_MULTICAST_REC_OK == res->error_code) - { - struct GNUNET_CONTAINER_MultiHashMap * - grp_replay_req_client = GNUNET_CONTAINER_multihashmap_get (replay_req_client, - &grp->pub_key_hash); - if (NULL != grp_replay_req_client) - { - GNUNET_CONTAINER_multihashmap_get_multiple (grp_replay_req_client, &key_hash, - client_send_replay_response_cb, - (void *) msg); - } - } - else - { - handle_client_replay_response_end (c, res); - return; - } - GNUNET_SERVICE_client_continue (client); -} - - -/** - * A new client connected. - * - * @param cls NULL - * @param client client to add - * @param mq message queue for @a client - * @return @a client - */ -static void * -client_notify_connect (void *cls, - struct GNUNET_SERVICE_Client *client, - struct GNUNET_MQ_Handle *mq) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client connected: %p\n", client); - /* FIXME: send connect ACK */ - - struct Client *c = GNUNET_new (struct Client); - c->client = client; - - return c; -} - - -/** - * Called whenever a client is disconnected. - * Frees our resources associated with that client. - * - * @param cls closure - * @param client identification of the client - * @param app_ctx must match @a client - */ -static void -client_notify_disconnect (void *cls, - struct GNUNET_SERVICE_Client *client, - void *app_ctx) -{ - struct Client *c = app_ctx; - struct Group *grp = c->group; - GNUNET_free (c); - - if (NULL == grp) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%p User context is NULL in client_disconnect()\n", grp); - GNUNET_break (0); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Client (%s) disconnected from group %s\n", - grp, (GNUNET_YES == grp->is_origin) ? "origin" : "member", - GNUNET_h2s (&grp->pub_key_hash)); - - // FIXME (due to protocol change): here we must not remove all clients, - // only the one we were notified about! - struct ClientList *cl = grp->clients_head; - while (NULL != cl) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "iterating clients for group %p\n", - grp); - if (cl->client == client) - { - GNUNET_CONTAINER_DLL_remove (grp->clients_head, grp->clients_tail, cl); - GNUNET_free (cl); - break; - } - cl = cl->next; - } - - while (GNUNET_YES == replay_req_remove_client (grp, client)); - - if (NULL == grp->clients_head) - { /* Last client disconnected. */ - cleanup_group (grp); - } -} - - -/** - * Service started. - * - * @param cls closure - * @param server the initialized server - * @param cfg configuration to use - */ -static void -run (void *cls, - const struct GNUNET_CONFIGURATION_Handle *c, - struct GNUNET_SERVICE_Handle *svc) -{ - cfg = c; - service = svc; - GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer); - - stats = GNUNET_STATISTICS_create ("multicast", cfg); - origins = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); - members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); - group_members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - channels_in = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); - channels_out = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); - replay_req_cadet = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - replay_req_client = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - - cadet = GNUNET_CADET_connect (cfg); - - GNUNET_assert (NULL != cadet); - - GNUNET_SCHEDULER_add_shutdown (&shutdown_task, - NULL); -} - - -/** - * Define "main" method using service macro. - */ -GNUNET_SERVICE_MAIN -("multicast", - GNUNET_SERVICE_OPTION_NONE, - &run, - &client_notify_connect, - &client_notify_disconnect, - NULL, - GNUNET_MQ_hd_fixed_size (client_origin_start, - GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START, - struct MulticastOriginStartMessage, - NULL), - GNUNET_MQ_hd_var_size (client_member_join, - GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN, - struct MulticastMemberJoinMessage, - NULL), - GNUNET_MQ_hd_var_size (client_join_decision, - GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION, - struct MulticastJoinDecisionMessageHeader, - NULL), - GNUNET_MQ_hd_fixed_size (client_part_request, - GNUNET_MESSAGE_TYPE_MULTICAST_PART_REQUEST, - struct GNUNET_MessageHeader, - NULL), - GNUNET_MQ_hd_var_size (client_multicast_message, - GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE, - struct GNUNET_MULTICAST_MessageHeader, - NULL), - GNUNET_MQ_hd_var_size (client_multicast_request, - GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST, - struct GNUNET_MULTICAST_RequestHeader, - NULL), - GNUNET_MQ_hd_fixed_size (client_replay_request, - GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST, - struct MulticastReplayRequestMessage, - NULL), - GNUNET_MQ_hd_var_size (client_replay_response, - GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE, - struct MulticastReplayResponseMessage, - NULL), - GNUNET_MQ_hd_var_size (client_replay_response_end, - GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE_END, - struct MulticastReplayResponseMessage, - NULL)); - -/* end of gnunet-service-multicast.c */ diff --git a/src/multicast/multicast.conf.in b/src/multicast/multicast.conf.in deleted file mode 100644 index 97a541336..000000000 --- a/src/multicast/multicast.conf.in +++ /dev/null @@ -1,22 +0,0 @@ -[multicast] -START_ON_DEMAND = @START_ON_DEMAND@ -BINARY = gnunet-service-multicast - -UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock -UNIX_MATCH_UID = YES -UNIX_MATCH_GID = YES - -@UNIXONLY@PORT = 2109 -HOSTNAME = localhost -ACCEPT_FROM = 127.0.0.1; -ACCEPT_FROM6 = ::1; - -# DISABLE_SOCKET_FORWARDING = NO -# USERNAME = -# MAXBUF = -# TIMEOUT = -# DISABLEV6 = -# BINDTO = -# REJECT_FROM = -# REJECT_FROM6 = -# PREFIX = diff --git a/src/multicast/multicast.h b/src/multicast/multicast.h deleted file mode 100644 index 8a3ca14c8..000000000 --- a/src/multicast/multicast.h +++ /dev/null @@ -1,303 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012, 2013 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later -*/ - -/** - * @file multicast/multicast.h - * @brief multicast IPC messages - * @author Christian Grothoff - * @author Gabor X Toth - */ -#ifndef MULTICAST_H -#define MULTICAST_H - -#include "platform.h" -#include "gnunet_multicast_service.h" - -GNUNET_NETWORK_STRUCT_BEGIN - - -/** - * Header of a join request sent to the origin or another member. - */ -struct MulticastJoinRequestMessage -{ - /** - * Type: GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST - */ - struct GNUNET_MessageHeader header; - - /** - * Always zero. - */ - uint32_t reserved; - - /** - * ECC signature of the rest of the fields of the join request. - * - * Signature must match the public key of the joining member. - */ - struct GNUNET_CRYPTO_EcdsaSignature signature; - - /** - * Purpose for the signature and size of the signed data. - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - - /** - * Public key of the target group. - */ - struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key; - - /** - * Public key of the joining member. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; - - /** - * Peer identity of the joining member. - */ - struct GNUNET_PeerIdentity peer; - - /* Followed by struct GNUNET_MessageHeader join_message */ -}; - - -/** - * Header of a join decision message sent to a peer requesting join. - */ -struct MulticastJoinDecisionMessage -{ - /** - * Type: GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION - */ - struct GNUNET_MessageHeader header; - - /** - * #GNUNET_YES if the peer was admitted - * #GNUNET_NO if entry was refused, - * #GNUNET_SYSERR if the request could not be answered. - */ - int32_t is_admitted; - - /** - * Number of relays given. - */ - uint32_t relay_count; - - /* Followed by relay_count peer identities */ - - /* Followed by the join response message */ -}; - - -/** - * Header added to a struct MulticastJoinDecisionMessage - * when sent between the client and service. - */ -struct MulticastJoinDecisionMessageHeader -{ - /** - * Type: GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION - */ - struct GNUNET_MessageHeader header; - - /** - * C->S: Peer to send the join decision to. - * S->C: Peer we received the join decision from. - */ - struct GNUNET_PeerIdentity peer; - - /** - * C->S: Public key of the member requesting join. - * S->C: Unused. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; - - /* Followed by struct MulticastJoinDecisionMessage */ -}; - - -/** - * Message sent from the client to the service to notify the service - * about the result of a membership test. - */ -struct MulticastMembershipTestResultMessage -{ - /** - * Type: GNUNET_MESSAGE_TYPE_MULTICAST_MEMBERSHIP_TEST_RESULT - */ - struct GNUNET_MessageHeader header; - - /** - * Unique ID that identifies the associated membership test. - */ - uint32_t uid; - - /** - * #GNUNET_YES if the peer is a member - * #GNUNET_NO if peer is not a member, - * #GNUNET_SYSERR if the test could not be answered. - */ - int32_t is_admitted; -}; - - -/** - * Message sent from the client to the service OR the service to the - * client asking for a message fragment to be replayed. - */ -struct MulticastReplayRequestMessage -{ - - /** - * The message type should be - * #GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST. - */ - struct GNUNET_MessageHeader header; - - /** - * S->C: Public key of the member requesting replay. - * C->S: Unused. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; - - /** - * ID of the message that is being requested. - */ - uint64_t fragment_id; - - /** - * ID of the message that is being requested. - */ - uint64_t message_id; - - /** - * Offset of the fragment that is being requested. - */ - uint64_t fragment_offset; - - /** - * Additional flags for the request. - */ - uint64_t flags; - - /** - * Replay request ID. - */ - uint32_t uid; -}; - - -/** - * Message sent from the client to the service to give the service - * a replayed message. - */ -struct MulticastReplayResponseMessage -{ - - /** - * Type: GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE - * or GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE_END - */ - struct GNUNET_MessageHeader header; - - /** - * ID of the message that is being requested. - */ - uint64_t fragment_id; - - /** - * ID of the message that is being requested. - */ - uint64_t message_id; - - /** - * Offset of the fragment that is being requested. - */ - uint64_t fragment_offset; - - /** - * Additional flags for the request. - */ - uint64_t flags; - - /** - * An `enum GNUNET_MULTICAST_ReplayErrorCode` identifying issues (in NBO). - */ - int32_t error_code; - - /* followed by replayed message */ -}; - - -/** - * Message sent from the client to the service to notify the service - * about the starting of a multicast group with this peers as its origin. - */ -struct MulticastOriginStartMessage -{ - /** - * Type: GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START - */ - struct GNUNET_MessageHeader header; - - /** - * Always zero. - */ - uint32_t reserved; - - /** - * Private, non-ephemeral key for the multicast group. - */ - struct GNUNET_CRYPTO_EddsaPrivateKey group_key; - - /** - * Last fragment ID sent to the group, used to continue counting fragments if - * we resume operating * a group. - */ - uint64_t max_fragment_id; -}; - - -struct MulticastMemberJoinMessage -{ - /** - * Type: GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN - */ - struct GNUNET_MessageHeader header; - - uint32_t relay_count GNUNET_PACKED; - - struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key; - - struct GNUNET_CRYPTO_EcdsaPrivateKey member_key; - - struct GNUNET_PeerIdentity origin; - - /* Followed by struct GNUNET_PeerIdentity relays[relay_count] */ - - /* Followed by struct GNUNET_MessageHeader join_msg */ -}; - - -GNUNET_NETWORK_STRUCT_END - -#endif -/* end of multicast.h */ diff --git a/src/multicast/multicast_api.c b/src/multicast/multicast_api.c deleted file mode 100644 index e5e830225..000000000 --- a/src/multicast/multicast_api.c +++ /dev/null @@ -1,1399 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012, 2013 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later -*/ - -/** - * @file multicast/multicast_api.c - * @brief Multicast service; implements multicast groups using CADET connections. - * @author Christian Grothoff - * @author Gabor X Toth - */ - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_multicast_service.h" -#include "multicast.h" - -#define LOG(kind,...) GNUNET_log_from (kind, "multicast-api",__VA_ARGS__) - - -/** - * Handle for a request to send a message to all multicast group members - * (from the origin). - */ -struct GNUNET_MULTICAST_OriginTransmitHandle -{ - GNUNET_MULTICAST_OriginTransmitNotify notify; - void *notify_cls; - struct GNUNET_MULTICAST_Origin *origin; - - uint64_t message_id; - uint64_t group_generation; - uint64_t fragment_offset; -}; - - -/** - * Handle for a message to be delivered from a member to the origin. - */ -struct GNUNET_MULTICAST_MemberTransmitHandle -{ - GNUNET_MULTICAST_MemberTransmitNotify notify; - void *notify_cls; - struct GNUNET_MULTICAST_Member *member; - - uint64_t request_id; - uint64_t fragment_offset; -}; - - -struct GNUNET_MULTICAST_Group -{ - /** - * Configuration to use. - */ - const struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * Client connection to the service. - */ - struct GNUNET_MQ_Handle *mq; - - /** - * Message to send on connect. - */ - struct GNUNET_MQ_Envelope *connect_env; - - /** - * Time to wait until we try to reconnect on failure. - */ - struct GNUNET_TIME_Relative reconnect_delay; - - /** - * Task for reconnecting when the listener fails. - */ - struct GNUNET_SCHEDULER_Task *reconnect_task; - - GNUNET_MULTICAST_JoinRequestCallback join_req_cb; - GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb; - GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb; - GNUNET_MULTICAST_MessageCallback message_cb; - void *cb_cls; - - /** - * Function called after disconnected from the service. - */ - GNUNET_ContinuationCallback disconnect_cb; - - /** - * Closure for @a disconnect_cb. - */ - void *disconnect_cls; - - /** - * Are we currently transmitting a message? - */ - uint8_t in_transmit; - - /** - * Number of MULTICAST_FRAGMENT_ACK messages we are still waiting for. - */ - uint8_t acks_pending; - - /** - * Is this the origin or a member? - */ - uint8_t is_origin; - - /** - * Is this channel in the process of disconnecting from the service? - * #GNUNET_YES or #GNUNET_NO - */ - uint8_t is_disconnecting; -}; - - -/** - * Handle for the origin of a multicast group. - */ -struct GNUNET_MULTICAST_Origin -{ - struct GNUNET_MULTICAST_Group grp; - struct GNUNET_MULTICAST_OriginTransmitHandle tmit; - - GNUNET_MULTICAST_RequestCallback request_cb; -}; - - -/** - * Handle for a multicast group member. - */ -struct GNUNET_MULTICAST_Member -{ - struct GNUNET_MULTICAST_Group grp; - struct GNUNET_MULTICAST_MemberTransmitHandle tmit; - - GNUNET_MULTICAST_JoinDecisionCallback join_dcsn_cb; - - /** - * Replay fragment -> struct GNUNET_MULTICAST_MemberReplayHandle * - */ - struct GNUNET_CONTAINER_MultiHashMap *replay_reqs; - - uint64_t next_fragment_id; -}; - - -/** - * Handle that identifies a join request. - * - * Used to match calls to #GNUNET_MULTICAST_JoinRequestCallback to the - * corresponding calls to #GNUNET_MULTICAST_join_decision(). - */ -struct GNUNET_MULTICAST_JoinHandle -{ - struct GNUNET_MULTICAST_Group *group; - - /** - * Public key of the member requesting join. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; - - /** - * Peer identity of the member requesting join. - */ - struct GNUNET_PeerIdentity peer; -}; - - -/** - * Opaque handle to a replay request from the multicast service. - */ -struct GNUNET_MULTICAST_ReplayHandle -{ - struct GNUNET_MULTICAST_Group *grp; - struct MulticastReplayRequestMessage req; -}; - - -/** - * Handle for a replay request. - */ -struct GNUNET_MULTICAST_MemberReplayHandle -{ -}; - - -static void -origin_to_all (struct GNUNET_MULTICAST_Origin *orig); - -static void -member_to_origin (struct GNUNET_MULTICAST_Member *mem); - - -/** - * Check join request message. - */ -static int -check_group_join_request (void *cls, - const struct MulticastJoinRequestMessage *jreq) -{ - uint16_t size = ntohs (jreq->header.size); - - if (sizeof (*jreq) == size) - return GNUNET_OK; - - if (sizeof (*jreq) + sizeof (struct GNUNET_MessageHeader) <= size) - return GNUNET_OK; - - return GNUNET_SYSERR; -} - - -/** - * Receive join request from service. - */ -static void -handle_group_join_request (void *cls, - const struct MulticastJoinRequestMessage *jreq) -{ - struct GNUNET_MULTICAST_Group *grp = cls; - struct GNUNET_MULTICAST_JoinHandle *jh; - const struct GNUNET_MessageHeader *jmsg = NULL; - - if (NULL == grp) - { - GNUNET_break (0); - return; - } - if (NULL == grp->join_req_cb) - return; - - if (sizeof (*jreq) + sizeof (*jmsg) <= ntohs (jreq->header.size)) - jmsg = (const struct GNUNET_MessageHeader *) &jreq[1]; - - jh = GNUNET_malloc (sizeof (*jh)); - jh->group = grp; - jh->member_pub_key = jreq->member_pub_key; - jh->peer = jreq->peer; - grp->join_req_cb (grp->cb_cls, &jreq->member_pub_key, jmsg, jh); - - grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; -} - - -/** - * Check multicast message. - */ -static int -check_group_message (void *cls, - const struct GNUNET_MULTICAST_MessageHeader *mmsg) -{ - return GNUNET_OK; -} - - -/** - * Receive multicast message from service. - */ -static void -handle_group_message (void *cls, - const struct GNUNET_MULTICAST_MessageHeader *mmsg) -{ - struct GNUNET_MULTICAST_Group *grp = cls; - - if (GNUNET_YES == grp->is_disconnecting) - return; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Calling message callback with a message of size %u.\n", - ntohs (mmsg->header.size)); - - if (NULL != grp->message_cb) - grp->message_cb (grp->cb_cls, mmsg); - - grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; -} - - -/** - * Receive message/request fragment acknowledgement from service. - */ -static void -handle_group_fragment_ack (void *cls, - const struct GNUNET_MessageHeader *msg) -{ - struct GNUNET_MULTICAST_Group *grp = cls; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "%p Got fragment ACK. in_transmit=%u, acks_pending=%u\n", - grp, grp->in_transmit, grp->acks_pending); - - if (0 == grp->acks_pending) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "%p Ignoring extraneous fragment ACK.\n", grp); - return; - } - grp->acks_pending--; - - if (GNUNET_YES != grp->in_transmit) - return; - - if (GNUNET_YES == grp->is_origin) - origin_to_all ((struct GNUNET_MULTICAST_Origin *) grp); - else - member_to_origin ((struct GNUNET_MULTICAST_Member *) grp); - - grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; -} - - -/** - * Check unicast request. - */ -static int -check_origin_request (void *cls, - const struct GNUNET_MULTICAST_RequestHeader *req) -{ - return GNUNET_OK; -} - - -/** - * Origin receives unicast request from a member. - */ -static void -handle_origin_request (void *cls, - const struct GNUNET_MULTICAST_RequestHeader *req) -{ - struct GNUNET_MULTICAST_Group *grp; - struct GNUNET_MULTICAST_Origin *orig = cls; - grp = &orig->grp; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Calling request callback with a request of size %u.\n", - ntohs (req->header.size)); - - if (NULL != orig->request_cb) - orig->request_cb (grp->cb_cls, req); - - grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; -} - - -/** - * Receive multicast replay request from service. - */ -static void -handle_group_replay_request (void *cls, - const struct MulticastReplayRequestMessage *rep) - -{ - struct GNUNET_MULTICAST_Group *grp = cls; - - if (GNUNET_YES == grp->is_disconnecting) - return; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got replay request.\n"); - - if (0 != rep->fragment_id) - { - if (NULL != grp->replay_frag_cb) - { - struct GNUNET_MULTICAST_ReplayHandle * rh = GNUNET_malloc (sizeof (*rh)); - rh->grp = grp; - rh->req = *rep; - grp->replay_frag_cb (grp->cb_cls, &rep->member_pub_key, - GNUNET_ntohll (rep->fragment_id), - GNUNET_ntohll (rep->flags), rh); - } - } - else if (0 != rep->message_id) - { - if (NULL != grp->replay_msg_cb) - { - struct GNUNET_MULTICAST_ReplayHandle * rh = GNUNET_malloc (sizeof (*rh)); - rh->grp = grp; - rh->req = *rep; - grp->replay_msg_cb (grp->cb_cls, &rep->member_pub_key, - GNUNET_ntohll (rep->message_id), - GNUNET_ntohll (rep->fragment_offset), - GNUNET_ntohll (rep->flags), rh); - } - } - - grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; -} - - -/** - * Check replay response. - */ -static int -check_member_replay_response (void *cls, - const struct MulticastReplayResponseMessage *res) -{ - uint16_t size = ntohs (res->header.size); - - if (sizeof (*res) == size) - return GNUNET_OK; - - if (sizeof (*res) + sizeof (struct GNUNET_MULTICAST_MessageHeader) <= size) - return GNUNET_OK; - - return GNUNET_SYSERR; -} - - -/** - * Receive replay response from service. - */ -static void -handle_member_replay_response (void *cls, - const struct MulticastReplayResponseMessage *res) -{ - struct GNUNET_MULTICAST_Group *grp; - struct GNUNET_MULTICAST_Member *mem = cls; - grp = &mem->grp; - - if (GNUNET_YES == grp->is_disconnecting) - return; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got replay response.\n"); - - // FIXME: return result -} - - -/** - * Check join decision. - */ -static int -check_member_join_decision (void *cls, - const struct MulticastJoinDecisionMessageHeader *hdcsn) -{ - return GNUNET_OK; // checked in handle below -} - - -/** - * Member receives join decision. - */ -static void -handle_member_join_decision (void *cls, - const struct MulticastJoinDecisionMessageHeader *hdcsn) -{ - struct GNUNET_MULTICAST_Group *grp; - struct GNUNET_MULTICAST_Member *mem = cls; - grp = &mem->grp; - - const struct MulticastJoinDecisionMessage * - dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1]; - - uint16_t dcsn_size = ntohs (dcsn->header.size); - int is_admitted = ntohl (dcsn->is_admitted); - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "%p Member got join decision from multicast: %d\n", - mem, is_admitted); - - const struct GNUNET_MessageHeader *join_resp = NULL; - uint16_t join_resp_size = 0; - - uint16_t relay_count = ntohl (dcsn->relay_count); - const struct GNUNET_PeerIdentity *relays = NULL; - uint16_t relay_size = relay_count * sizeof (*relays); - if (0 < relay_count) - { - if (dcsn_size < sizeof (*dcsn) + relay_size) - { - GNUNET_break_op (0); - is_admitted = GNUNET_SYSERR; - } - else - { - relays = (struct GNUNET_PeerIdentity *) &dcsn[1]; - } - } - - if (sizeof (*dcsn) + relay_size + sizeof (*join_resp) <= dcsn_size) - { - join_resp = (const struct GNUNET_MessageHeader *) ((char *) &dcsn[1] + relay_size); - join_resp_size = ntohs (join_resp->size); - } - if (dcsn_size < sizeof (*dcsn) + relay_size + join_resp_size) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received invalid join decision message from multicast: %u < %u + %u + %u\n", - dcsn_size , sizeof (*dcsn), relay_size, join_resp_size); - GNUNET_break_op (0); - is_admitted = GNUNET_SYSERR; - } - - if (NULL != mem->join_dcsn_cb) - mem->join_dcsn_cb (grp->cb_cls, is_admitted, &hdcsn->peer, - relay_count, relays, join_resp); - - // FIXME: - //if (GNUNET_YES != is_admitted) - // GNUNET_MULTICAST_member_part (mem); - - grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; -} - - -static void -group_cleanup (struct GNUNET_MULTICAST_Group *grp) -{ - if (NULL != grp->connect_env) - { - GNUNET_MQ_discard (grp->connect_env); - grp->connect_env = NULL; - } - if (NULL != grp->mq) - { - GNUNET_MQ_destroy (grp->mq); - grp->mq = NULL; - } - if (NULL != grp->disconnect_cb) - { - grp->disconnect_cb (grp->disconnect_cls); - grp->disconnect_cb = NULL; - } - GNUNET_free (grp); -} - - -static void -handle_group_part_ack (void *cls, - const struct GNUNET_MessageHeader *msg) -{ - struct GNUNET_MULTICAST_Group *grp = cls; - - group_cleanup (grp); -} - - -/** - * Function to call with the decision made for a join request. - * - * Must be called once and only once in response to an invocation of the - * #GNUNET_MULTICAST_JoinRequestCallback. - * - * @param join - * Join request handle. - * @param is_admitted - * #GNUNET_YES if the join is approved, - * #GNUNET_NO if it is disapproved, - * #GNUNET_SYSERR if we cannot answer the request. - * @param relay_count - * Number of relays given. - * @param relays - * Array of suggested peers that might be useful relays to use - * when joining the multicast group (essentially a list of peers that - * are already part of the multicast group and might thus be willing - * to help with routing). If empty, only this local peer (which must - * be the multicast origin) is a good candidate for building the - * multicast tree. Note that it is unnecessary to specify our own - * peer identity in this array. - * @param join_resp - * Message to send in response to the joining peer; - * can also be used to redirect the peer to a different group at the - * application layer; this response is to be transmitted to the - * peer that issued the request even if admission is denied. - */ -struct GNUNET_MULTICAST_ReplayHandle * -GNUNET_MULTICAST_join_decision (struct GNUNET_MULTICAST_JoinHandle *join, - int is_admitted, - uint16_t relay_count, - const struct GNUNET_PeerIdentity *relays, - const struct GNUNET_MessageHeader *join_resp) -{ - struct GNUNET_MULTICAST_Group *grp = join->group; - uint16_t join_resp_size = (NULL != join_resp) ? ntohs (join_resp->size) : 0; - uint16_t relay_size = relay_count * sizeof (*relays); - - struct MulticastJoinDecisionMessageHeader *hdcsn; - struct MulticastJoinDecisionMessage *dcsn; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (hdcsn, sizeof (*dcsn) + relay_size + join_resp_size, - GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION); - hdcsn->member_pub_key = join->member_pub_key; - hdcsn->peer = join->peer; - - dcsn = (struct MulticastJoinDecisionMessage *) &hdcsn[1]; - dcsn->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION); - dcsn->header.size = htons (sizeof (*dcsn) + relay_size + join_resp_size); - dcsn->is_admitted = htonl (is_admitted); - dcsn->relay_count = htonl (relay_count); - if (0 < relay_size) - GNUNET_memcpy (&dcsn[1], relays, relay_size); - if (0 < join_resp_size) - GNUNET_memcpy (((char *) &dcsn[1]) + relay_size, join_resp, join_resp_size); - - GNUNET_MQ_send (grp->mq, env); - GNUNET_free (join); - return NULL; -} - - -/** - * Replay a message fragment for the multicast group. - * - * @param rh - * Replay handle identifying which replay operation was requested. - * @param msg - * Replayed message fragment, NULL if not found / an error occurred. - * @param ec - * Error code. See enum GNUNET_MULTICAST_ReplayErrorCode - * If not #GNUNET_MULTICAST_REC_OK, the replay handle is invalidated. - */ -void -GNUNET_MULTICAST_replay_response (struct GNUNET_MULTICAST_ReplayHandle *rh, - const struct GNUNET_MessageHeader *msg, - enum GNUNET_MULTICAST_ReplayErrorCode ec) -{ - uint8_t msg_size = (NULL != msg) ? ntohs (msg->size) : 0; - struct MulticastReplayResponseMessage *res; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (res, msg_size, - GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE); - res->fragment_id = rh->req.fragment_id; - res->message_id = rh->req.message_id; - res->fragment_offset = rh->req.fragment_offset; - res->flags = rh->req.flags; - res->error_code = htonl (ec); - - if (GNUNET_MULTICAST_REC_OK == ec) - { - GNUNET_assert (NULL != msg); - GNUNET_memcpy (&res[1], msg, msg_size); - } - - GNUNET_MQ_send (rh->grp->mq, env); - - if (GNUNET_MULTICAST_REC_OK != ec) - GNUNET_free (rh); -} - - -/** - * Indicate the end of the replay session. - * - * Invalidates the replay handle. - * - * @param rh - * Replay session to end. - */ -void -GNUNET_MULTICAST_replay_response_end (struct GNUNET_MULTICAST_ReplayHandle *rh) -{ - struct MulticastReplayResponseMessage *end; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg (end, GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE_END); - - end->fragment_id = rh->req.fragment_id; - end->message_id = rh->req.message_id; - end->fragment_offset = rh->req.fragment_offset; - end->flags = rh->req.flags; - - GNUNET_MQ_send (rh->grp->mq, env); - GNUNET_free (rh); -} - - -/** - * Replay a message for the multicast group. - * - * @param rh - * Replay handle identifying which replay operation was requested. - * @param notify - * Function to call to get the message. - * @param notify_cls - * Closure for @a notify. - */ -void -GNUNET_MULTICAST_replay_response2 (struct GNUNET_MULTICAST_ReplayHandle *rh, - GNUNET_MULTICAST_ReplayTransmitNotify notify, - void *notify_cls) -{ -} - - -static void -origin_connect (struct GNUNET_MULTICAST_Origin *orig); - - -static void -origin_reconnect (void *cls) -{ - origin_connect (cls); -} - - -/** - * Origin client disconnected from service. - * - * Reconnect after backoff period. - */ -static void -origin_disconnected (void *cls, enum GNUNET_MQ_Error error) -{ - struct GNUNET_MULTICAST_Origin *orig = cls; - struct GNUNET_MULTICAST_Group *grp = &orig->grp; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Origin client disconnected (%d), re-connecting\n", - (int) error); - if (NULL != grp->mq) - { - GNUNET_MQ_destroy (grp->mq); - grp->mq = NULL; - } - - grp->reconnect_task = GNUNET_SCHEDULER_add_delayed (grp->reconnect_delay, - origin_reconnect, - orig); - grp->reconnect_delay = GNUNET_TIME_STD_BACKOFF (grp->reconnect_delay); -} - - -/** - * Connect to service as origin. - */ -static void -origin_connect (struct GNUNET_MULTICAST_Origin *orig) -{ - struct GNUNET_MULTICAST_Group *grp = &orig->grp; - - struct GNUNET_MQ_MessageHandler handlers[] = { - GNUNET_MQ_hd_var_size (group_message, - GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE, - struct GNUNET_MULTICAST_MessageHeader, - grp), - GNUNET_MQ_hd_var_size (origin_request, - GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST, - struct GNUNET_MULTICAST_RequestHeader, - orig), - GNUNET_MQ_hd_fixed_size (group_fragment_ack, - GNUNET_MESSAGE_TYPE_MULTICAST_FRAGMENT_ACK, - struct GNUNET_MessageHeader, - grp), - GNUNET_MQ_hd_var_size (group_join_request, - GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST, - struct MulticastJoinRequestMessage, - grp), - GNUNET_MQ_hd_fixed_size (group_part_ack, - GNUNET_MESSAGE_TYPE_MULTICAST_PART_ACK, - struct GNUNET_MessageHeader, - grp), - GNUNET_MQ_hd_fixed_size (group_replay_request, - GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST, - struct MulticastReplayRequestMessage, - grp), - GNUNET_MQ_handler_end () - }; - - grp->mq = GNUNET_CLIENT_connect (grp->cfg, "multicast", - handlers, origin_disconnected, orig); - GNUNET_assert (NULL != grp->mq); - GNUNET_MQ_send_copy (grp->mq, grp->connect_env); -} - - -/** - * Start a multicast group. - * - * Will advertise the origin in the P2P overlay network under the respective - * public key so that other peer can find this peer to join it. Peers that - * issue GNUNET_MULTICAST_member_join() can then transmit a join request to - * either an existing group member or to the origin. If the joining is - * approved, the member is cleared for @e replay and will begin to receive - * messages transmitted to the group. If joining is disapproved, the failed - * candidate will be given a response. Members in the group can send messages - * to the origin (one at a time). - * - * @param cfg - * Configuration to use. - * @param priv_key - * ECC key that will be used to sign messages for this - * multicast session; public key is used to identify the multicast group; - * @param max_fragment_id - * Maximum fragment ID already sent to the group. - * 0 for a new group. - * @param join_request_cb - * Function called to approve / disapprove joining of a peer. - * @param replay_frag_cb - * Function that can be called to replay a message fragment. - * @param replay_msg_cb - * Function that can be called to replay a message. - * @param request_cb - * Function called with message fragments from group members. - * @param message_cb - * Function called with the message fragments sent to the - * network by GNUNET_MULTICAST_origin_to_all(). These message fragments - * should be stored for answering replay requests later. - * @param cls - * Closure for the various callbacks that follow. - * - * @return Handle for the origin, NULL on error. - */ -struct GNUNET_MULTICAST_Origin * -GNUNET_MULTICAST_origin_start (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_CRYPTO_EddsaPrivateKey *priv_key, - uint64_t max_fragment_id, - GNUNET_MULTICAST_JoinRequestCallback join_request_cb, - GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb, - GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb, - GNUNET_MULTICAST_RequestCallback request_cb, - GNUNET_MULTICAST_MessageCallback message_cb, - void *cls) -{ - struct GNUNET_MULTICAST_Origin *orig = GNUNET_malloc (sizeof (*orig)); - struct GNUNET_MULTICAST_Group *grp = &orig->grp; - - struct MulticastOriginStartMessage *start; - grp->connect_env = GNUNET_MQ_msg (start, - GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START); - start->max_fragment_id = max_fragment_id; - start->group_key = *priv_key; - - grp->cfg = cfg; - grp->is_origin = GNUNET_YES; - grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; - - grp->cb_cls = cls; - grp->join_req_cb = join_request_cb; - grp->replay_frag_cb = replay_frag_cb; - grp->replay_msg_cb = replay_msg_cb; - grp->message_cb = message_cb; - - orig->request_cb = request_cb; - - origin_connect (orig); - return orig; -} - - -/** - * Stop a multicast group. - * - * @param origin - * Multicast group to stop. - */ -void -GNUNET_MULTICAST_origin_stop (struct GNUNET_MULTICAST_Origin *orig, - GNUNET_ContinuationCallback stop_cb, - void *stop_cls) -{ - struct GNUNET_MULTICAST_Group *grp = &orig->grp; - struct GNUNET_MQ_Envelope *env; - - grp->is_disconnecting = GNUNET_YES; - grp->disconnect_cb = stop_cb; - grp->disconnect_cls = stop_cls; - env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_PART_REQUEST); - GNUNET_MQ_send (grp->mq, env); -} - - -static void -origin_to_all (struct GNUNET_MULTICAST_Origin *orig) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "%p origin_to_all()\n", orig); - struct GNUNET_MULTICAST_Group *grp = &orig->grp; - struct GNUNET_MULTICAST_OriginTransmitHandle *tmit = &orig->tmit; - GNUNET_assert (GNUNET_YES == grp->in_transmit); - - size_t buf_size = GNUNET_MULTICAST_FRAGMENT_MAX_SIZE; - struct GNUNET_MULTICAST_MessageHeader *msg; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (msg, buf_size - sizeof(*msg), - GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE); - - int ret = tmit->notify (tmit->notify_cls, &buf_size, &msg[1]); - - if (! (GNUNET_YES == ret || GNUNET_NO == ret) - || GNUNET_MULTICAST_FRAGMENT_MAX_SIZE < buf_size) - { - LOG (GNUNET_ERROR_TYPE_ERROR, - "%p OriginTransmitNotify() returned error or invalid message size.\n", - orig); - /* FIXME: handle error */ - GNUNET_MQ_discard (env); - return; - } - - if (GNUNET_NO == ret && 0 == buf_size) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "%p OriginTransmitNotify() - transmission paused.\n", orig); - GNUNET_MQ_discard (env); - return; /* Transmission paused. */ - } - - msg->header.size = htons (sizeof (*msg) + buf_size); - msg->message_id = GNUNET_htonll (tmit->message_id); - msg->group_generation = tmit->group_generation; - msg->fragment_offset = GNUNET_htonll (tmit->fragment_offset); - tmit->fragment_offset += sizeof (*msg) + buf_size; - - grp->acks_pending++; - GNUNET_MQ_send (grp->mq, env); - - if (GNUNET_YES == ret) - grp->in_transmit = GNUNET_NO; -} - - -/** - * Send a message to the multicast group. - * - * @param orig - * Handle to the multicast group. - * @param message_id - * Application layer ID for the message. Opaque to multicast. - * @param group_generation - * Group generation of the message. - * Documented in struct GNUNET_MULTICAST_MessageHeader. - * @param notify - * Function to call to get the message. - * @param notify_cls - * Closure for @a notify. - * - * @return Message handle on success, - * NULL on error (i.e. another request is already pending). - */ -struct GNUNET_MULTICAST_OriginTransmitHandle * -GNUNET_MULTICAST_origin_to_all (struct GNUNET_MULTICAST_Origin *orig, - uint64_t message_id, - uint64_t group_generation, - GNUNET_MULTICAST_OriginTransmitNotify notify, - void *notify_cls) -{ - struct GNUNET_MULTICAST_Group *grp = &orig->grp; - if (GNUNET_YES == grp->in_transmit) - return NULL; - grp->in_transmit = GNUNET_YES; - - struct GNUNET_MULTICAST_OriginTransmitHandle *tmit = &orig->tmit; - tmit->origin = orig; - tmit->message_id = message_id; - tmit->fragment_offset = 0; - tmit->group_generation = group_generation; - tmit->notify = notify; - tmit->notify_cls = notify_cls; - - origin_to_all (orig); - return tmit; -} - - -/** - * Resume message transmission to multicast group. - * - * @param th - * Transmission to cancel. - */ -void -GNUNET_MULTICAST_origin_to_all_resume (struct GNUNET_MULTICAST_OriginTransmitHandle *th) -{ - struct GNUNET_MULTICAST_Group *grp = &th->origin->grp; - if (0 != grp->acks_pending || GNUNET_YES != grp->in_transmit) - return; - origin_to_all (th->origin); -} - - -/** - * Cancel request for message transmission to multicast group. - * - * @param th - * Transmission to cancel. - */ -void -GNUNET_MULTICAST_origin_to_all_cancel (struct GNUNET_MULTICAST_OriginTransmitHandle *th) -{ - th->origin->grp.in_transmit = GNUNET_NO; -} - - -static void -member_connect (struct GNUNET_MULTICAST_Member *mem); - - -static void -member_reconnect (void *cls) -{ - member_connect (cls); -} - - -/** - * Member client disconnected from service. - * - * Reconnect after backoff period. - */ -static void -member_disconnected (void *cls, enum GNUNET_MQ_Error error) -{ - struct GNUNET_MULTICAST_Member *mem = cls; - struct GNUNET_MULTICAST_Group *grp = &mem->grp; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Member client disconnected (%d), re-connecting\n", - (int) error); - GNUNET_MQ_destroy (grp->mq); - grp->mq = NULL; - - grp->reconnect_task = GNUNET_SCHEDULER_add_delayed (grp->reconnect_delay, - member_reconnect, - mem); - grp->reconnect_delay = GNUNET_TIME_STD_BACKOFF (grp->reconnect_delay); -} - - -/** - * Connect to service as member. - */ -static void -member_connect (struct GNUNET_MULTICAST_Member *mem) -{ - struct GNUNET_MULTICAST_Group *grp = &mem->grp; - - struct GNUNET_MQ_MessageHandler handlers[] = { - GNUNET_MQ_hd_var_size (group_message, - GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE, - struct GNUNET_MULTICAST_MessageHeader, - grp), - GNUNET_MQ_hd_fixed_size (group_fragment_ack, - GNUNET_MESSAGE_TYPE_MULTICAST_FRAGMENT_ACK, - struct GNUNET_MessageHeader, - grp), - GNUNET_MQ_hd_var_size (group_join_request, - GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST, - struct MulticastJoinRequestMessage, - grp), - GNUNET_MQ_hd_var_size (member_join_decision, - GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION, - struct MulticastJoinDecisionMessageHeader, - mem), - GNUNET_MQ_hd_fixed_size (group_part_ack, - GNUNET_MESSAGE_TYPE_MULTICAST_PART_ACK, - struct GNUNET_MessageHeader, - grp), - GNUNET_MQ_hd_fixed_size (group_replay_request, - GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST, - struct MulticastReplayRequestMessage, - grp), - GNUNET_MQ_hd_var_size (member_replay_response, - GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE, - struct MulticastReplayResponseMessage, - mem), - GNUNET_MQ_handler_end () - }; - - grp->mq = GNUNET_CLIENT_connect (grp->cfg, "multicast", - handlers, member_disconnected, mem); - GNUNET_assert (NULL != grp->mq); - GNUNET_MQ_send_copy (grp->mq, grp->connect_env); -} - - -/** - * Join a multicast group. - * - * The entity joining is always the local peer. Further information about the - * candidate can be provided in the @a join_request message. If the join fails, the - * @a message_cb is invoked with a (failure) response and then with NULL. If - * the join succeeds, outstanding (state) messages and ongoing multicast - * messages will be given to the @a message_cb until the member decides to part - * the group. The @a replay_cb function may be called at any time by the - * multicast service to support relaying messages to other members of the group. - * - * @param cfg - * Configuration to use. - * @param group_key - * ECC public key that identifies the group to join. - * @param member_key - * ECC key that identifies the member - * and used to sign requests sent to the origin. - * @param origin - * Peer ID of the origin to send unicast requsets to. If NULL, - * unicast requests are sent back via multiple hops on the reverse path - * of multicast messages. - * @param relay_count - * Number of peers in the @a relays array. - * @param relays - * Peer identities of members of the group, which serve as relays - * and can be used to join the group at. and send the @a join_request to. - * If empty, the @a join_request is sent directly to the @a origin. - * @param join_msg - * Application-dependent join message to be passed to the peer @a origin. - * @param join_request_cb - * Function called to approve / disapprove joining of a peer. - * @param join_decision_cb - * Function called to inform about the join decision. - * @param replay_frag_cb - * Function that can be called to replay message fragments - * this peer already knows from this group. NULL if this - * client is unable to support replay. - * @param replay_msg_cb - * Function that can be called to replay message fragments - * this peer already knows from this group. NULL if this - * client is unable to support replay. - * @param message_cb - * Function to be called for all message fragments we - * receive from the group, excluding those our @a replay_cb - * already has. - * @param cls - * Closure for callbacks. - * - * @return Handle for the member, NULL on error. - */ -struct GNUNET_MULTICAST_Member * -GNUNET_MULTICAST_member_join (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_CRYPTO_EddsaPublicKey *group_pub_key, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key, - const struct GNUNET_PeerIdentity *origin, - uint16_t relay_count, - const struct GNUNET_PeerIdentity *relays, - const struct GNUNET_MessageHeader *join_msg, - GNUNET_MULTICAST_JoinRequestCallback join_request_cb, - GNUNET_MULTICAST_JoinDecisionCallback join_decision_cb, - GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb, - GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb, - GNUNET_MULTICAST_MessageCallback message_cb, - void *cls) -{ - struct GNUNET_MULTICAST_Member *mem = GNUNET_malloc (sizeof (*mem)); - struct GNUNET_MULTICAST_Group *grp = &mem->grp; - - uint16_t relay_size = relay_count * sizeof (*relays); - uint16_t join_msg_size = (NULL != join_msg) ? ntohs (join_msg->size) : 0; - struct MulticastMemberJoinMessage *join; - grp->connect_env = GNUNET_MQ_msg_extra (join, relay_size + join_msg_size, - GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN); - join->group_pub_key = *group_pub_key; - join->member_key = *member_key; - join->origin = *origin; - join->relay_count = ntohl (relay_count); - if (0 < relay_size) - GNUNET_memcpy (&join[1], relays, relay_size); - if (0 < join_msg_size) - GNUNET_memcpy (((char *) &join[1]) + relay_size, join_msg, join_msg_size); - - grp->cfg = cfg; - grp->is_origin = GNUNET_NO; - grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; - - mem->join_dcsn_cb = join_decision_cb; - grp->join_req_cb = join_request_cb; - grp->replay_frag_cb = replay_frag_cb; - grp->replay_msg_cb = replay_msg_cb; - grp->message_cb = message_cb; - grp->cb_cls = cls; - - member_connect (mem); - return mem; -} - - -/** - * Part a multicast group. - * - * Disconnects from all group members and invalidates the @a member handle. - * - * An application-dependent part message can be transmitted beforehand using - * #GNUNET_MULTICAST_member_to_origin()) - * - * @param member - * Membership handle. - */ -void -GNUNET_MULTICAST_member_part (struct GNUNET_MULTICAST_Member *mem, - GNUNET_ContinuationCallback part_cb, - void *part_cls) -{ - struct GNUNET_MULTICAST_Group *grp = &mem->grp; - struct GNUNET_MQ_Envelope *env; - - mem->join_dcsn_cb = NULL; - grp->join_req_cb = NULL; - grp->message_cb = NULL; - grp->replay_msg_cb = NULL; - grp->replay_frag_cb = NULL; - grp->is_disconnecting = GNUNET_YES; - grp->disconnect_cb = part_cb; - grp->disconnect_cls = part_cls; - env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_PART_REQUEST); - GNUNET_MQ_send (grp->mq, env); -} - - -void -member_replay_request (struct GNUNET_MULTICAST_Member *mem, - uint64_t fragment_id, - uint64_t message_id, - uint64_t fragment_offset, - uint64_t flags) -{ - struct MulticastReplayRequestMessage *rep; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg (rep, GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST); - - rep->fragment_id = GNUNET_htonll (fragment_id); - rep->message_id = GNUNET_htonll (message_id); - rep->fragment_offset = GNUNET_htonll (fragment_offset); - rep->flags = GNUNET_htonll (flags); - - GNUNET_MQ_send (mem->grp.mq, env); -} - - -/** - * Request a fragment to be replayed by fragment ID. - * - * Useful if messages below the @e max_known_fragment_id given when joining are - * needed and not known to the client. - * - * @param member - * Membership handle. - * @param fragment_id - * ID of a message fragment that this client would like to see replayed. - * @param flags - * Additional flags for the replay request. - * It is used and defined by GNUNET_MULTICAST_ReplayFragmentCallback - * - * @return Replay request handle. - */ -struct GNUNET_MULTICAST_MemberReplayHandle * -GNUNET_MULTICAST_member_replay_fragment (struct GNUNET_MULTICAST_Member *mem, - uint64_t fragment_id, - uint64_t flags) -{ - member_replay_request (mem, fragment_id, 0, 0, flags); - // FIXME: return something useful - return NULL; -} - - -/** - * Request a message fragment to be replayed. - * - * Useful if messages below the @e max_known_fragment_id given when joining are - * needed and not known to the client. - * - * @param member - * Membership handle. - * @param message_id - * ID of the message this client would like to see replayed. - * @param fragment_offset - * Offset of the fragment within the message to replay. - * @param flags - * Additional flags for the replay request. - * It is used & defined by GNUNET_MULTICAST_ReplayMessageCallback - * - * @return Replay request handle, NULL on error. - */ -struct GNUNET_MULTICAST_MemberReplayHandle * -GNUNET_MULTICAST_member_replay_message (struct GNUNET_MULTICAST_Member *mem, - uint64_t message_id, - uint64_t fragment_offset, - uint64_t flags) -{ - member_replay_request (mem, 0, message_id, fragment_offset, flags); - // FIXME: return something useful - return NULL; -} - - -static void -member_to_origin (struct GNUNET_MULTICAST_Member *mem) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "member_to_origin()\n"); - struct GNUNET_MULTICAST_Group *grp = &mem->grp; - struct GNUNET_MULTICAST_MemberTransmitHandle *tmit = &mem->tmit; - GNUNET_assert (GNUNET_YES == grp->in_transmit); - - size_t buf_size = GNUNET_MULTICAST_FRAGMENT_MAX_SIZE; - struct GNUNET_MULTICAST_RequestHeader *req; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (req, buf_size - sizeof(*req), - GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST); - - int ret = tmit->notify (tmit->notify_cls, &buf_size, &req[1]); - - if (! (GNUNET_YES == ret || GNUNET_NO == ret) - || GNUNET_MULTICAST_FRAGMENT_MAX_SIZE < buf_size) - { - LOG (GNUNET_ERROR_TYPE_ERROR, - "MemberTransmitNotify() returned error or invalid message size. " - "ret=%d, buf_size=%u\n", ret, buf_size); - /* FIXME: handle error */ - GNUNET_MQ_discard (env); - return; - } - - if (GNUNET_NO == ret && 0 == buf_size) - { - /* Transmission paused. */ - GNUNET_MQ_discard (env); - return; - } - - req->header.size = htons (sizeof (*req) + buf_size); - req->request_id = GNUNET_htonll (tmit->request_id); - req->fragment_offset = GNUNET_ntohll (tmit->fragment_offset); - tmit->fragment_offset += sizeof (*req) + buf_size; - - GNUNET_MQ_send (grp->mq, env); - - if (GNUNET_YES == ret) - grp->in_transmit = GNUNET_NO; -} - - -/** - * Send a message to the origin of the multicast group. - * - * @param mem - * Membership handle. - * @param request_id - * Application layer ID for the request. Opaque to multicast. - * @param notify - * Callback to call to get the message. - * @param notify_cls - * Closure for @a notify. - * - * @return Handle to cancel request, NULL on error (i.e. request already pending). - */ -struct GNUNET_MULTICAST_MemberTransmitHandle * -GNUNET_MULTICAST_member_to_origin (struct GNUNET_MULTICAST_Member *mem, - uint64_t request_id, - GNUNET_MULTICAST_MemberTransmitNotify notify, - void *notify_cls) -{ - if (GNUNET_YES == mem->grp.in_transmit) - return NULL; - mem->grp.in_transmit = GNUNET_YES; - - struct GNUNET_MULTICAST_MemberTransmitHandle *tmit = &mem->tmit; - tmit->member = mem; - tmit->request_id = request_id; - tmit->fragment_offset = 0; - tmit->notify = notify; - tmit->notify_cls = notify_cls; - - member_to_origin (mem); - return tmit; -} - - -/** - * Resume message transmission to origin. - * - * @param th - * Transmission to cancel. - */ -void -GNUNET_MULTICAST_member_to_origin_resume (struct GNUNET_MULTICAST_MemberTransmitHandle *th) -{ - struct GNUNET_MULTICAST_Group *grp = &th->member->grp; - if (0 != grp->acks_pending || GNUNET_YES != grp->in_transmit) - return; - member_to_origin (th->member); -} - - -/** - * Cancel request for message transmission to origin. - * - * @param th - * Transmission to cancel. - */ -void -GNUNET_MULTICAST_member_to_origin_cancel (struct GNUNET_MULTICAST_MemberTransmitHandle *th) -{ - th->member->grp.in_transmit = GNUNET_NO; -} - - -/* end of multicast_api.c */ diff --git a/src/multicast/test_multicast.c b/src/multicast/test_multicast.c deleted file mode 100644 index 70efdcbfb..000000000 --- a/src/multicast/test_multicast.c +++ /dev/null @@ -1,758 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file multicast/test_multicast.c - * @brief Tests for the Multicast API. - * @author Gabor X Toth - */ - -#include - -#include "platform.h" -#include "gnunet_crypto_lib.h" -#include "gnunet_common.h" -#include "gnunet_util_lib.h" -#include "gnunet_testing_lib.h" -#include "gnunet_multicast_service.h" - -#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) - -/** - * Return value from 'main'. - */ -static int res; - -/** - * Handle for task for timeout termination. - */ -static struct GNUNET_SCHEDULER_Task * end_badly_task; - -static const struct GNUNET_CONFIGURATION_Handle *cfg; - -struct GNUNET_PeerIdentity this_peer; - -struct GNUNET_MULTICAST_Origin *origin; -struct GNUNET_MULTICAST_Member *member; - -struct GNUNET_CRYPTO_EddsaPrivateKey *group_key; -struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key; - -struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key; -struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; - -struct TransmitClosure { - struct GNUNET_MULTICAST_OriginTransmitHandle *orig_tmit; - struct GNUNET_MULTICAST_MemberTransmitHandle *mem_tmit; - char * data[16]; - uint8_t data_delay[16]; - uint8_t data_count; - uint8_t paused; - uint8_t n; -} tmit_cls; - -struct OriginClosure { - uint8_t msgs_expected; - uint8_t n; -} origin_cls; - -struct MemberClosure { - uint8_t msgs_expected; - size_t n; -} member_cls; - -struct GNUNET_MessageHeader *join_req, *join_resp; - -enum -{ - TEST_NONE = 0, - TEST_ORIGIN_START = 1, - TEST_MEMBER_JOIN_REFUSE = 2, - TEST_MEMBER_JOIN_ADMIT = 3, - TEST_ORIGIN_TO_ALL = 4, - TEST_ORIGIN_TO_ALL_RECV = 5, - TEST_MEMBER_TO_ORIGIN = 6, - TEST_MEMBER_REPLAY_ERROR = 7, - TEST_MEMBER_REPLAY_OK = 8, - TEST_MEMBER_PART = 9, - TEST_ORIGIN_STOP = 10, -} test; - -uint64_t replay_fragment_id; -uint64_t replay_flags; - -static void -member_join (int t); - - -/** - * Clean up all resources used. - */ -static void -cleanup () -{ - if (NULL != member) - { - GNUNET_MULTICAST_member_part (member, NULL, NULL); - member = NULL; - } - if (NULL != origin) - { - GNUNET_MULTICAST_origin_stop (origin, NULL, NULL); - origin = NULL; - } -} - - -/** - * Terminate the test case (failure). - * - * @param cls NULL - */ -static void -end_badly (void *cls) -{ - res = 1; - cleanup (); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test FAILED.\n"); -} - - -/** - * Terminate the test case (success). - * - * @param cls NULL - */ -static void -end_normally (void *cls) -{ - res = 0; - cleanup (); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Test PASSED.\n"); -} - - -/** - * Finish the test case (successfully). - */ -static void -end () -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending tests.\n"); - - if (end_badly_task != NULL) - { - GNUNET_SCHEDULER_cancel (end_badly_task); - end_badly_task = NULL; - } - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, - &end_normally, NULL); -} - - -static void -tmit_resume (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission resumed.\n"); - struct TransmitClosure *tmit = cls; - if (NULL != tmit->orig_tmit) - GNUNET_MULTICAST_origin_to_all_resume (tmit->orig_tmit); - else if (NULL != tmit->mem_tmit) - GNUNET_MULTICAST_member_to_origin_resume (tmit->mem_tmit); -} - - -static int -tmit_notify (void *cls, size_t *data_size, void *data) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Test #%u: origin_tmit_notify()\n", test); - struct TransmitClosure *tmit = cls; - - if (0 == tmit->data_count) - { - *data_size = 0; - return GNUNET_YES; - } - - uint16_t size = strlen (tmit->data[tmit->n]); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Transmit notify data: %u bytes available, processing fragment %u/%u (size %u).\n", - (unsigned int) *data_size, - tmit->n + 1, - tmit->data_count, - size); - if (*data_size < size) - { - *data_size = 0; - GNUNET_assert (0); - return GNUNET_SYSERR; - } - - if (GNUNET_YES != tmit->paused && 0 < tmit->data_delay[tmit->n]) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission paused.\n"); - tmit->paused = GNUNET_YES; - GNUNET_SCHEDULER_add_delayed ( - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, - tmit->data_delay[tmit->n]), - tmit_resume, tmit); - *data_size = 0; - return GNUNET_NO; - } - tmit->paused = GNUNET_NO; - - *data_size = size; - GNUNET_memcpy (data, tmit->data[tmit->n], size); - - return ++tmit->n < tmit->data_count ? GNUNET_NO : GNUNET_YES; -} - - -static void -member_recv_join_request (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key, - const struct GNUNET_MessageHeader *join_msg, - struct GNUNET_MULTICAST_JoinHandle *jh) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%u: member_recv_join_request()\n", test); -} - - -static void -origin_stopped (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%u: origin_stopped()\n", test); - end (); -} - - -static void -schedule_origin_stop (void *cls) -{ - test = TEST_ORIGIN_STOP; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%u: origin_stop()\n", test); - GNUNET_MULTICAST_origin_stop (origin, origin_stopped, NULL); - origin = NULL; -} - - -static void -member_parted (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%u: member_parted()\n", test); - member = NULL; - - switch (test) - { - case TEST_MEMBER_JOIN_REFUSE: - // Test 3 starts here - member_join (TEST_MEMBER_JOIN_ADMIT); - break; - - case TEST_MEMBER_PART: - GNUNET_SCHEDULER_add_now (&schedule_origin_stop, NULL); - break; - - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Invalid test #%d in member_parted()\n", test); - GNUNET_assert (0); - } -} - - -static void -schedule_member_part (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%u: schedule_member_part()\n", test); - GNUNET_MULTICAST_member_part (member, member_parted, NULL); -} - - -static void -member_part () -{ - test = TEST_MEMBER_PART; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%u: member_part()\n", test); - // Test 10 starts here - GNUNET_SCHEDULER_add_now (&schedule_member_part, NULL); -} - - -static void -member_replay_ok () -{ - // Execution of test 8 here - test = TEST_MEMBER_REPLAY_OK; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%u: member_replay_ok()\n", test); - replay_fragment_id = 1; - replay_flags = 1 | 1<<11; - GNUNET_MULTICAST_member_replay_fragment (member, replay_fragment_id, - replay_flags); -} - - -static void -member_replay_error () -{ - test = TEST_MEMBER_REPLAY_ERROR; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%u: member_replay_error()\n", test); - replay_fragment_id = 1234; - replay_flags = 11 | 1<<11; - GNUNET_MULTICAST_member_replay_fragment (member, replay_fragment_id, - replay_flags); -} - - -static void -origin_recv_replay_msg (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key, - uint64_t message_id, - uint64_t fragment_offset, - uint64_t flags, - struct GNUNET_MULTICAST_ReplayHandle *rh) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%u: origin_recv_replay_msg()\n", test); - GNUNET_assert (0); -} - - -static void -member_recv_replay_msg (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key, - uint64_t message_id, - uint64_t fragment_offset, - uint64_t flags, - struct GNUNET_MULTICAST_ReplayHandle *rh) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%u: member_recv_replay_msg()\n", test); - GNUNET_assert (0); -} - - -static void -origin_recv_replay_frag (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key, - uint64_t fragment_id, - uint64_t flags, - struct GNUNET_MULTICAST_ReplayHandle *rh) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%u: origin_recv_replay_frag()" - " - fragment_id=%" PRIu64 " flags=%" PRIu64 "\n", - test, fragment_id, flags); - GNUNET_assert (replay_fragment_id == fragment_id && replay_flags == flags); - switch (test) - { - case TEST_MEMBER_REPLAY_ERROR: - // Test 8 starts here - GNUNET_MULTICAST_replay_response (rh, NULL, GNUNET_SYSERR); - member_replay_ok (); - break; - - case TEST_MEMBER_REPLAY_OK: - { - struct GNUNET_MULTICAST_MessageHeader mmsg = { - .header = { - .type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE), - .size = htons (sizeof (mmsg)), - }, - .fragment_id = GNUNET_htonll (1), - .message_id = GNUNET_htonll (1), - .fragment_offset = 0, - .group_generation = GNUNET_htonll (1), - .flags = 0, - }; - member_cls.n = 0; - member_cls.msgs_expected = 1; - GNUNET_MULTICAST_replay_response (rh, &mmsg.header, GNUNET_MULTICAST_REC_OK); - GNUNET_MULTICAST_replay_response_end (rh); - break; - } - - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Invalid test #%d in origin_recv_replay_frag()\n", test); - GNUNET_assert (0); - } -} - - -static void -member_recv_replay_frag (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key, - uint64_t fragment_id, - uint64_t flags, - struct GNUNET_MULTICAST_ReplayHandle *rh) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%u: member_recv_replay_frag()\n", test); - GNUNET_assert (0); -} - - -static void -origin_recv_request (void *cls, - const struct GNUNET_MULTICAST_RequestHeader *req) -{ - struct OriginClosure *ocls = cls; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%u: origin_recv_request()\n", test); - if (++ocls->n != ocls->msgs_expected) - return; - - GNUNET_assert (0 == memcmp (&req->member_pub_key, - &member_pub_key, sizeof (member_pub_key))); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Test #%u: verify message content, take first 3 bytes: %.3s\n", - test, (char *)&req[1]); - GNUNET_assert (0 == memcmp (&req[1], "abc", 3)); - - // Test 7 starts here - member_replay_error (); -} - - -static void -member_to_origin () -{ - test = TEST_MEMBER_TO_ORIGIN; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%u: member_to_origin()\n", test); - - struct TransmitClosure *tmit = &tmit_cls; - *tmit = (struct TransmitClosure) {}; - tmit->data[0] = "abc def"; - tmit->data[1] = "ghi jkl mno"; - tmit->data_delay[1] = 2; - tmit->data[2] = "pqr stuw xyz"; - tmit->data_count = 3; - - origin_cls.n = 0; - origin_cls.msgs_expected = 1; - - tmit->mem_tmit = GNUNET_MULTICAST_member_to_origin (member, 1, - tmit_notify, tmit); -} - - -static void -member_recv_message (void *cls, - const struct GNUNET_MULTICAST_MessageHeader *msg) -{ - struct MemberClosure *mcls = cls; - - // Test 5 starts here after message has been received from origin - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Test #%u: member_recv_message() %u/%u\n", - test, - (unsigned int) (mcls->n + 1), - mcls->msgs_expected); - if (++mcls->n != mcls->msgs_expected) - return; - - // FIXME: check message content - - switch (test) - { - case TEST_ORIGIN_TO_ALL: - test = TEST_ORIGIN_TO_ALL_RECV; - break; - - case TEST_ORIGIN_TO_ALL_RECV: - // Test 6 starts here - member_to_origin (); - break; - - case TEST_MEMBER_REPLAY_OK: - // Test 9 starts here - GNUNET_assert (replay_fragment_id == GNUNET_ntohll (msg->fragment_id)); - member_part (); - break; - - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Invalid test #%d in origin_recv_message()\n", test); - GNUNET_assert (0); - } -} - - -static void -origin_recv_message (void *cls, - const struct GNUNET_MULTICAST_MessageHeader *msg) -{ - struct OriginClosure *ocls = cls; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%u: origin_recv_message() %u/%u\n", - test, ocls->n + 1, ocls->msgs_expected); - if (++ocls->n != ocls->msgs_expected) - return; - - // FIXME: check message content - - switch (test) - { - case TEST_ORIGIN_TO_ALL: - // Prepare to execute test 5 - test = TEST_ORIGIN_TO_ALL_RECV; - break; - - case TEST_ORIGIN_TO_ALL_RECV: - // Test 6 starts here - member_to_origin (); - break; - - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Invalid test #%d in origin_recv_message()\n", test); - GNUNET_assert (0); - } -} - - -static void -origin_to_all () -{ - test = TEST_ORIGIN_TO_ALL; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%u: origin_to_all()\n", test); - - struct TransmitClosure *tmit = &tmit_cls; - *tmit = (struct TransmitClosure) {}; - tmit->data[0] = "ABC DEF"; - tmit->data[1] = GNUNET_malloc (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD + 1); - uint16_t i; - for (i = 0; i < GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD; i++) - tmit->data[1][i] = (0 == i % 10000) ? '0' + i / 10000 : '_'; - tmit->data[2] = "GHI JKL MNO"; - tmit->data_delay[2] = 2; - tmit->data[3] = "PQR STUW XYZ"; - tmit->data_count = 4; - - origin_cls.n = member_cls.n = 0; - origin_cls.msgs_expected = member_cls.msgs_expected = tmit->data_count; - - tmit->orig_tmit = GNUNET_MULTICAST_origin_to_all (origin, 1, 1, - tmit_notify, tmit); -} - - -static void -member_recv_join_decision (void *cls, - int is_admitted, - const struct GNUNET_PeerIdentity *peer, - uint16_t relay_count, - const struct GNUNET_PeerIdentity *relays, - const struct GNUNET_MessageHeader *join_msg) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%u: member_recv_join_decision() - is_admitted: %d\n", - test, is_admitted); - - GNUNET_assert (join_msg->size == join_resp->size); - GNUNET_assert (join_msg->type == join_resp->type); - GNUNET_assert (0 == memcmp (join_msg, join_resp, ntohs (join_resp->size))); - - switch (test) - { - case TEST_MEMBER_JOIN_REFUSE: - GNUNET_assert (0 == relay_count); - // Test 3 starts here - GNUNET_SCHEDULER_add_now (&schedule_member_part, NULL); - break; - - case TEST_MEMBER_JOIN_ADMIT: - GNUNET_assert (1 == relay_count); - GNUNET_assert (0 == memcmp (relays, &this_peer, sizeof (this_peer))); - // Test 4 starts here - origin_to_all (); - break; - - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Invalid test #%d in member_recv_join_decision()\n", test); - GNUNET_assert (0); - } -} - -/** - * Test: origin receives join request - */ -static void -origin_recv_join_request (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *mem_key, - const struct GNUNET_MessageHeader *join_msg, - struct GNUNET_MULTICAST_JoinHandle *jh) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%u: origin_recv_join_request()\n", test); - - GNUNET_assert (0 == memcmp (mem_key, &member_pub_key, sizeof (member_pub_key))); - GNUNET_assert (join_msg->size == join_req->size); - GNUNET_assert (join_msg->type == join_req->type); - GNUNET_assert (0 == memcmp (join_msg, join_req, ntohs (join_req->size))); - - char data[] = "here's the decision"; - uint8_t data_size = strlen (data) + 1; - join_resp = GNUNET_malloc (sizeof (join_resp) + data_size); - join_resp->size = htons (sizeof (join_resp) + data_size); - join_resp->type = htons (456); - GNUNET_memcpy (&join_resp[1], data, data_size); - - switch (test) - { - case TEST_MEMBER_JOIN_REFUSE: - // Test 3 starts here - GNUNET_MULTICAST_join_decision (jh, GNUNET_NO, 0, NULL, join_resp); - break; - - case TEST_MEMBER_JOIN_ADMIT: - // Test 3 is running - GNUNET_MULTICAST_join_decision (jh, GNUNET_YES, 1, &this_peer, join_resp); - break; - - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Invalid test #%d in origin_recv_join_request()\n", test); - GNUNET_assert (0); - break; - } -} - -/** - * Test: member joins multicast group - */ -static void -member_join (int t) -{ - test = t; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%u: member_join()\n", test); - - member_key = GNUNET_CRYPTO_ecdsa_key_create (); - GNUNET_CRYPTO_ecdsa_key_get_public (member_key, &member_pub_key); - - if (NULL != join_req) - GNUNET_free (join_req); - - char data[] = "let me in!"; - uint8_t data_size = strlen (data) + 1; - join_req = GNUNET_malloc (sizeof (join_req) + data_size); - join_req->size = htons (sizeof (join_req) + data_size); - join_req->type = htons (123); - GNUNET_memcpy (&join_req[1], data, data_size); - - member = GNUNET_MULTICAST_member_join (cfg, &group_pub_key, member_key, - &this_peer, 1, &this_peer, join_req, - member_recv_join_request, - member_recv_join_decision, - member_recv_replay_frag, - member_recv_replay_msg, - member_recv_message, - &member_cls); -} - -/** - * Test: Start a multicast group as origin - */ -static void -origin_start () -{ - test = TEST_ORIGIN_START; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%u: origin_start()\n", test); - - group_key = GNUNET_CRYPTO_eddsa_key_create (); - GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key); - - origin = GNUNET_MULTICAST_origin_start (cfg, group_key, 0, - origin_recv_join_request, - origin_recv_replay_frag, - origin_recv_replay_msg, - origin_recv_request, - origin_recv_message, - &origin_cls); - // Test 2 starts here - member_join (TEST_MEMBER_JOIN_REFUSE); -} - - -/** - * Main function of the test, run from scheduler. - * - * @param cls NULL - * @param cfg configuration we use (also to connect to Multicast service) - * @param peer handle to access more of the peer (not used) - */ -static void -#if DEBUG_TEST_MULTICAST -run (void *cls, - char *const *args, - const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *c) -#else -run (void *cls, - const struct GNUNET_CONFIGURATION_Handle *c, - struct GNUNET_TESTING_Peer *peer) -#endif -{ - cfg = c; - end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, - &end_badly, NULL); - GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer); - - // Test 1 starts here - origin_start (); -} - - -int -main (int argc, char *argv[]) -{ - res = 1; -#if DEBUG_TEST_MULTICAST - const struct GNUNET_GETOPT_CommandLineOption opts[] = { - GNUNET_GETOPT_OPTION_END - }; - if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-multicast", - "test-multicast [options]", - opts, &run, NULL)) - return 1; -#else - if (0 != GNUNET_TESTING_peer_run ("test-multicast", "test_multicast.conf", &run, NULL)) - return 1; -#endif - return res; -} - -/* end of test_multicast.c */ diff --git a/src/multicast/test_multicast.conf b/src/multicast/test_multicast.conf deleted file mode 100644 index b2f1a764b..000000000 --- a/src/multicast/test_multicast.conf +++ /dev/null @@ -1,56 +0,0 @@ -[testbed] -HOSTNAME = localhost - -[arm] -GLOBAL_POSTFIX=-L ERROR - -[multicast] -#PREFIX = tmux new-window gdb -x ./cmd.gdb --args -#PREFIX = valgrind --leak-check=full -UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock - -[vpn] -START_ON_DEMAND = NO - -[peerinfo] -# Do not use shipped gnunet HELLOs -USE_INCLUDED_HELLOS = NO - -# Option to disable all disk IO; only useful for testbed runs -# (large-scale experiments); disables persistence of HELLOs! -NO_IO = YES - -[hostlist] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[nat] -ENABLE_UPNP = NO - -[fs] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[vpn] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[revocation] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[gns] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[namestore] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[namecache] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[topology] -IMMEDIATE_START = NO -START_ON_DEMAND = NO diff --git a/src/multicast/test_multicast_2peers.c b/src/multicast/test_multicast_2peers.c deleted file mode 100644 index ea996026c..000000000 --- a/src/multicast/test_multicast_2peers.c +++ /dev/null @@ -1,520 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file multicast/test_multicast_2peers.c - * @brief Tests for the Multicast API with two peers doing the ping - * pong test. - * @author xrs - */ - -#include - -#include "platform.h" -#include "gnunet_crypto_lib.h" -#include "gnunet_common.h" -#include "gnunet_util_lib.h" -#include "gnunet_testbed_service.h" -#include "gnunet_multicast_service.h" - -#define NUM_PEERS 2 - -static struct GNUNET_TESTBED_Operation *op0; -static struct GNUNET_TESTBED_Operation *op1; -static struct GNUNET_TESTBED_Operation *pi_op0; -static struct GNUNET_TESTBED_Operation *pi_op1; - -static struct GNUNET_TESTBED_Peer **peers; -const struct GNUNET_PeerIdentity *peer_id[2]; - -static struct GNUNET_SCHEDULER_Task *timeout_tid; - -static struct GNUNET_MULTICAST_Origin *origin; -static struct GNUNET_MULTICAST_Member *member; - -struct GNUNET_CRYPTO_EddsaPrivateKey *group_key; -struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key; - -struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key; -struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; - -/** - * Global result for testcase. - */ -static int result; - - -/** - * Function run on CTRL-C or shutdown (i.e. success/timeout/etc.). - * Cleans up. - */ -static void -shutdown_task (void *cls) -{ - if (NULL != op0) - { - GNUNET_TESTBED_operation_done (op0); - op0 = NULL; - } - if (NULL != op1) - { - GNUNET_TESTBED_operation_done (op1); - op1 = NULL; - } - if (NULL != pi_op0) - { - GNUNET_TESTBED_operation_done (pi_op0); - pi_op0 = NULL; - } - if (NULL != pi_op1) - { - GNUNET_TESTBED_operation_done (pi_op1); - pi_op1 = NULL; - } - if (NULL != timeout_tid) - { - GNUNET_SCHEDULER_cancel (timeout_tid); - timeout_tid = NULL; - } -} - - -static void -timeout_task (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Timeout!\n"); - result = GNUNET_SYSERR; - GNUNET_SCHEDULER_shutdown (); -} - - -static void -member_join_request (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, - const struct GNUNET_MessageHeader *join_msg, - struct GNUNET_MULTICAST_JoinHandle *jh) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Member sent a join request.\n"); - -} - - -static int -notify (void *cls, - size_t *data_size, - void *data) -{ - - char text[] = "ping"; - *data_size = strlen(text)+1; - GNUNET_memcpy(data, text, *data_size); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Member sents message to origin: %s\n", text); - - return GNUNET_YES; -} - - -static void -member_join_decision (void *cls, - int is_admitted, - const struct GNUNET_PeerIdentity *peer, - uint16_t relay_count, - const struct GNUNET_PeerIdentity *relays, - const struct GNUNET_MessageHeader *join_msg) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Member received a decision from origin: %s\n", - (GNUNET_YES == is_admitted) - ? "accepted" - : "rejected"); - - if (GNUNET_YES == is_admitted) - { - struct GNUNET_MULTICAST_MemberTransmitHandle *req; - - // FIXME: move to MQ-style API! - req = GNUNET_MULTICAST_member_to_origin (member, - 0, - ¬ify, - NULL); - } -} - - -static void -member_message (void *cls, - const struct GNUNET_MULTICAST_MessageHeader *msg) -{ - if (0 != strncmp ("pong", (char *)&msg[1], 4)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "member did not receive pong\n"); - result = GNUNET_SYSERR; - GNUNET_SCHEDULER_shutdown (); - } - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "member receives: %s\n", (char *)&msg[1]); - - // Testcase ends here. - result = GNUNET_YES; - GNUNET_SCHEDULER_shutdown (); -} - - -static void -origin_join_request (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, - const struct GNUNET_MessageHeader *join_msg, - struct GNUNET_MULTICAST_JoinHandle *jh) -{ - struct GNUNET_MessageHeader *join_resp; - - uint8_t data_size = ntohs (join_msg->size); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "origin got a join request...\n"); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "origin receives: '%s'\n", (char *)&join_msg[1]); - - const char data[] = "Come in!"; - data_size = strlen (data) + 1; - join_resp = GNUNET_malloc (sizeof (join_resp) + data_size); - join_resp->size = htons (sizeof (join_resp) + data_size); - join_resp->type = htons (123); - GNUNET_memcpy (&join_resp[1], data, data_size); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "origin sends: '%s'\n", data); - - GNUNET_MULTICAST_join_decision (jh, - GNUNET_YES, - 0, - NULL, - join_resp); - GNUNET_free (join_resp); - result = GNUNET_OK; -} - - -int -origin_notify (void *cls, - size_t *data_size, - void *data) -{ - char text[] = "pong"; - - *data_size = strlen(text)+1; - GNUNET_memcpy (data, - text, - *data_size); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin sends (to all): %s\n", text); - - return GNUNET_YES; -} - - -static void -origin_request (void *cls, - const struct GNUNET_MULTICAST_RequestHeader *req) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin receives: %s\n", (char *)&req[1]); - - if (0 != strncmp ("ping", (char *)&req[1], 4)) - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "origin didn't reveice a correct request"); - - GNUNET_MULTICAST_origin_to_all (origin, - 0, - 0, - origin_notify, - NULL); -} - - -static void -origin_message (void *cls, - const struct GNUNET_MULTICAST_MessageHeader *msg) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin message msg\n"); -} - - -static void -service_connect1 (void *cls, - struct GNUNET_TESTBED_Operation *op, - void *ca_result, - const char *emsg) -{ - member = ca_result; - - if (NULL == member) - { - result = GNUNET_SYSERR; - GNUNET_SCHEDULER_shutdown (); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to multicast service of member\n"); - } -} - - -static void -multicast_da1 (void *cls, - void * op_result) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Member parting from multicast group\n"); - - GNUNET_MULTICAST_member_part (member, NULL, NULL); -} - - -static void * -multicast_ca1 (void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct GNUNET_MessageHeader *join_msg; - void *ret; - - // Get members keys - member_key = GNUNET_CRYPTO_ecdsa_key_create (); - GNUNET_CRYPTO_ecdsa_key_get_public (member_key, &member_pub_key); - - char data[] = "Hi, can I enter?"; - uint8_t data_size = strlen (data) + 1; - join_msg = GNUNET_malloc (sizeof (join_msg) + data_size); - join_msg->size = htons (sizeof (join_msg) + data_size); - join_msg->type = htons (123); - GNUNET_memcpy (&join_msg[1], data, data_size); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Members tries to join multicast group\n"); - - ret = GNUNET_MULTICAST_member_join (cfg, - &group_pub_key, - member_key, - peer_id[0], - 0, - NULL, - join_msg, /* join message */ - member_join_request, - member_join_decision, - NULL, /* no test for member_replay_frag */ - NULL, /* no test for member_replay_msg */ - member_message, - NULL); - GNUNET_free (join_msg); - return ret; -} - - -static void -peer_information_cb (void *cls, - struct GNUNET_TESTBED_Operation *op, - const struct GNUNET_TESTBED_PeerInformation *pinfo, - const char *emsg) -{ - int i = (int) (long) cls; - - if (NULL == pinfo) - { - result = GNUNET_SYSERR; - GNUNET_SCHEDULER_shutdown (); - } - - peer_id[i] = pinfo->result.id; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Got peer information of %s (%s)\n", (0==i)?"origin":"member" ,GNUNET_i2s(pinfo->result.id)); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Create member peer\n"); - - if (0 == i) - { - /* connect to multicast service of member */ - op1 = GNUNET_TESTBED_service_connect (NULL, /* Closure for operation */ - peers[1], /* The peer whose service to connect to */ - "multicast", /* The name of the service */ - service_connect1, /* callback to call after a handle to service - is opened */ - NULL, /* closure for the above callback */ - multicast_ca1, /* callback to call with peer's configuration; - this should open the needed service connection */ - multicast_da1, /* callback to be called when closing the - opened service connection */ - NULL); /* closure for the above two callbacks */ - } -} - - -/** - * Test logic of peer "0" being origin starts here. - * - * @param cls closure, for the example: NULL - * @param op should be equal to "dht_op" - * @param ca_result result of the connect operation, the - * connection to the DHT service - * @param emsg error message, if testbed somehow failed to - * connect to the DHT. - */ -static void -service_connect0 (void *cls, - struct GNUNET_TESTBED_Operation *op, - void *ca_result, - const char *emsg) -{ - origin = ca_result; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Connected to multicast service of origin\n"); - - // Get GNUnet identity of origin - pi_op0 = GNUNET_TESTBED_peer_get_information (peers[0], - GNUNET_TESTBED_PIT_IDENTITY, - peer_information_cb, - (void *) 0); - // Get GNUnet identity of member - pi_op1 = GNUNET_TESTBED_peer_get_information (peers[1], - GNUNET_TESTBED_PIT_IDENTITY, - peer_information_cb, - (void *) 1); - - /* Connection to service successful. Here we'd usually do something with - * the service. */ - result = GNUNET_OK; - //GNUNET_SCHEDULER_shutdown (); /* Also kills the testbed */ -} - - - -/** - * Function run when service multicast has started and is providing us - * with a configuration file. - */ -static void * -multicast_ca0 (void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - group_key = GNUNET_CRYPTO_eddsa_key_create (); - GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key); - - return GNUNET_MULTICAST_origin_start (cfg, - group_key, - 0, - origin_join_request, - NULL, /* no test for origin_replay_frag */ - NULL, /* no test for origin_replay_msg */ - origin_request, - origin_message, - NULL); -} - -static void -multicast_da0 (void *cls, - void *op_result) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Origin closes multicast group\n"); - - GNUNET_MULTICAST_origin_stop (origin, NULL, NULL); -} - - -/** - * Main function inovked from TESTBED once all of the - * peers are up and running. This one then connects - * just to the multicast service of peer 0 and 1. - * Peer 0 is going to be origin. - * Peer 1 is going to be one member. - * Origin will start a multicast group and the member will try to join it. - * After that we execute some multicast test. - * - * @param cls closure - * @param h the run handle - * @param peers started peers for the test - * @param num_peers size of the 'peers' array - * @param links_succeeded number of links between peers that were created - * @param links_failed number of links testbed was unable to establish - */ -static void -testbed_master (void *cls, - struct GNUNET_TESTBED_RunHandle *h, - unsigned int num_peers, - struct GNUNET_TESTBED_Peer **p, - unsigned int links_succeeded, - unsigned int links_failed) -{ - /* Testbed is ready with peers running and connected in a pre-defined overlay - topology (FIXME) */ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Connected to testbed_master()\n"); - - peers = p; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Create origin peer\n"); - op0 = GNUNET_TESTBED_service_connect (NULL, /* Closure for operation */ - peers[0], /* The peer whose service to connect to */ - "multicast", /* The name of the service */ - service_connect0, /* callback to call after a handle to service - is opened */ - NULL, /* closure for the above callback */ - multicast_ca0, /* callback to call with peer's configuration; - this should open the needed service connection */ - multicast_da0, /* callback to be called when closing the - opened service connection */ - NULL); /* closure for the above two callbacks */ - - GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); /* Schedule a new task on shutdown */ - - /* Schedule the shutdown task with a delay of a few Seconds */ - timeout_tid = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 50), - &timeout_task, NULL); -} - - -int -main (int argc, char *argv[]) -{ - int ret; - - result = GNUNET_SYSERR; - ret = GNUNET_TESTBED_test_run - ("test-multicast-2peers", /* test case name */ - "test_multicast.conf", /* template configuration */ - NUM_PEERS, /* number of peers to start */ - 0LL, /* Event mask - set to 0 for no event notifications */ - NULL, /* Controller event callback */ - NULL, /* Closure for controller event callback */ - testbed_master, /* continuation callback to be called when testbed setup is complete */ - NULL); /* Closure for the test_master callback */ - if ( (GNUNET_OK != ret) || (GNUNET_OK != result) ) - return 1; - return 0; -} - - -/* end of test_multicast_2peers.c */ diff --git a/src/multicast/test_multicast_line.conf b/src/multicast/test_multicast_line.conf deleted file mode 100644 index c1ce7c63f..000000000 --- a/src/multicast/test_multicast_line.conf +++ /dev/null @@ -1,63 +0,0 @@ -[testbed] -HOSTNAME = localhost -OVERLAY_TOPOLOGY = LINE - -[arm] -GLOBAL_POSTFIX=-L ERROR - -[multicast] -#PREFIX = tmux new-window gdb -x ./cmd.gdb --args -#PREFIX = valgrind --leak-check=full -UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock - -[vpn] -START_ON_DEMAND = NO - -[peerinfo] -# Do not use shipped gnunet HELLOs -USE_INCLUDED_HELLOS = NO - -# Option to disable all disk IO; only useful for testbed runs -# (large-scale experiments); disables persistence of HELLOs! -NO_IO = YES - -[cadet] -ID_ANNOUNCE_TIME = 5 s - -[hostlist] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[nat] -ENABLE_UPNP = NO - -[fs] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[vpn] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[revocation] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[gns] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[namestore] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[namecache] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[topology] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[nse] -WORKBITS = 0 diff --git a/src/multicast/test_multicast_multipeer.c b/src/multicast/test_multicast_multipeer.c deleted file mode 100644 index 9b44e05db..000000000 --- a/src/multicast/test_multicast_multipeer.c +++ /dev/null @@ -1,643 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file multicast/test_multicast_multipeers.c - * @brief Tests for the Multicast API with multiple peers. - * @author xrs - */ - -#include - -#include "platform.h" -#include "gnunet_crypto_lib.h" -#include "gnunet_common.h" -#include "gnunet_util_lib.h" -#include "gnunet_testbed_service.h" -#include "gnunet_multicast_service.h" - -#define PEERS_REQUESTED 12 - -struct MulticastPeerContext -{ - int peer; /* peer number */ - struct GNUNET_CRYPTO_EcdsaPrivateKey *key; - const struct GNUNET_PeerIdentity *id; - struct GNUNET_TESTBED_Operation *op; /* not yet in use */ - struct GNUNET_TESTBED_Operation *pi_op; /* not yet in use */ - int test_ok; -}; - -enum pingpong -{ - PING = 1, - PONG = 2 -}; - -struct pingpong_msg -{ - int peer; - enum pingpong msg; -}; - -static void service_connect (void *cls, - struct GNUNET_TESTBED_Operation *op, - void *ca_result, - const char *emsg); - -static struct MulticastPeerContext **multicast_peers; -static struct GNUNET_TESTBED_Peer **peers; - -static struct GNUNET_TESTBED_Operation *op[PEERS_REQUESTED]; -static struct GNUNET_TESTBED_Operation *pi_op[PEERS_REQUESTED]; - -static struct GNUNET_MULTICAST_Origin *origin; -static struct GNUNET_MULTICAST_Member *members[PEERS_REQUESTED]; /* first element always empty */ - -static struct GNUNET_SCHEDULER_Task *timeout_tid; - -static struct GNUNET_CRYPTO_EddsaPrivateKey *group_key; -static struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key; -static struct GNUNET_HashCode group_pub_key_hash; - -/** - * Global result for testcase. - */ -static int result; - -/** - * Function run on CTRL-C or shutdown (i.e. success/timeout/etc.). - * Cleans up. - */ -static void -shutdown_task (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "shutdown_task!\n"); - for (int i=0;ikey); - GNUNET_free (multicast_peers[i]); - multicast_peers[i] = NULL; - } - GNUNET_free (multicast_peers); - multicast_peers = NULL; - } - - if (NULL != timeout_tid) - { - GNUNET_SCHEDULER_cancel (timeout_tid); - timeout_tid = NULL; - } -} - - -static void -timeout_task (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Timeout!\n"); - result = GNUNET_SYSERR; - GNUNET_SCHEDULER_shutdown (); -} - - -static void -member_join_request (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, - const struct GNUNET_MessageHeader *join_msg, - struct GNUNET_MULTICAST_JoinHandle *jh) -{ - struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Peer #%u (%s) sent a join request.\n", - mc_peer->peer, - GNUNET_i2s (multicast_peers[mc_peer->peer]->id)); -} - - -static int -notify (void *cls, - size_t *data_size, - void *data) -{ - struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls; - - struct pingpong_msg *pp_msg = GNUNET_new (struct pingpong_msg); - pp_msg->peer = mc_peer->peer; - pp_msg->msg = PING; - - *data_size = sizeof (struct pingpong_msg); - GNUNET_memcpy(data, pp_msg, *data_size); - GNUNET_free (pp_msg); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Peer #%u sents ping to origin\n", mc_peer->peer); - - return GNUNET_YES; -} - - -static void -member_join_decision (void *cls, - int is_admitted, - const struct GNUNET_PeerIdentity *peer, - uint16_t relay_count, - const struct GNUNET_PeerIdentity *relays, - const struct GNUNET_MessageHeader *join_msg) -{ - struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Peer #%u (%s) received a decision from origin: %s\n", - mc_peer->peer, - GNUNET_i2s (multicast_peers[mc_peer->peer]->id), - (GNUNET_YES == is_admitted)?"accepted":"rejected"); - - if (GNUNET_YES == is_admitted) - { - GNUNET_MULTICAST_member_to_origin (members[mc_peer->peer], - 0, - notify, - cls); - - } -} - - -static void -member_replay_frag () -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "member replay frag...\n"); -} - - -static void -member_replay_msg () -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "member replay msg...\n"); -} - - -static void -origin_disconnected_cb (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Origin disconnected. Shutting down.\n"); - result = GNUNET_YES; - GNUNET_SCHEDULER_shutdown (); -} - - -static void -member_disconnected_cb (void *cls) -{ - for (int i = 1; i < PEERS_REQUESTED; ++i) - if (GNUNET_NO == multicast_peers[i]->test_ok) - return; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "All member disconnected. Stopping origin.\n"); - GNUNET_MULTICAST_origin_stop (origin, origin_disconnected_cb, cls); -} - - -static void -member_message (void *cls, - const struct GNUNET_MULTICAST_MessageHeader *msg) -{ - struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls; - struct pingpong_msg *pp_msg = (struct pingpong_msg*) &(msg[1]); - - if (PONG == pp_msg->msg && mc_peer->peer == pp_msg->peer) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "peer #%i (%s) receives a pong\n", - mc_peer->peer, - GNUNET_i2s (multicast_peers[mc_peer->peer]->id)); - mc_peer->test_ok = GNUNET_OK; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "peer #%u (%s) parting from multicast group\n", - mc_peer->peer, - GNUNET_i2s (multicast_peers[mc_peer->peer]->id)); - - GNUNET_MULTICAST_member_part (members[mc_peer->peer], member_disconnected_cb, cls); - } -} - - -static void -origin_join_request (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, - const struct GNUNET_MessageHeader *join_msg, - struct GNUNET_MULTICAST_JoinHandle *jh) -{ - struct GNUNET_MessageHeader *join_resp; - - uint8_t data_size = ntohs (join_msg->size); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "origin got a join request...\n"); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "origin receives: '%s'\n", (char *)&join_msg[1]); - - char data[] = "Come in!"; - data_size = strlen (data) + 1; - join_resp = GNUNET_malloc (sizeof (join_resp) + data_size); - join_resp->size = htons (sizeof (join_resp) + data_size); - join_resp->type = htons (123); - GNUNET_memcpy (&join_resp[1], data, data_size); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "origin sends: '%s'\n", data); - - GNUNET_MULTICAST_join_decision (jh, - GNUNET_YES, - 0, - NULL, - join_resp); - - result = GNUNET_OK; -} - - -static void -origin_replay_frag (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, - uint64_t fragment_id, - uint64_t flags, - struct GNUNET_MULTICAST_ReplayHandle *rh) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin replay fraq msg\n"); -} - - -static void -origin_replay_msg (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, - uint64_t message_id, - uint64_t fragment_offset, - uint64_t flags, - struct GNUNET_MULTICAST_ReplayHandle *rh) -{ - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin replay msg\n"); -} - - -static int -origin_notify (void *cls, - size_t *data_size, - void *data) -{ - struct pingpong_msg *rcv_pp_msg = (struct pingpong_msg*)cls; - struct pingpong_msg *pp_msg = GNUNET_new (struct pingpong_msg); - - pp_msg->peer = rcv_pp_msg->peer; - pp_msg->msg = PONG; - *data_size = sizeof (struct pingpong_msg); - GNUNET_memcpy(data, pp_msg, *data_size); - GNUNET_free (pp_msg); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin sends pong\n"); - - return GNUNET_YES; -} - - -static void -origin_request (void *cls, - const struct GNUNET_MULTICAST_RequestHeader *req) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin receives a msg\n"); - - req++; - struct pingpong_msg *pp_msg = (struct pingpong_msg *) req; - - if (1 != pp_msg->msg) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "origin didn't reveice a correct request"); - } - - GNUNET_MULTICAST_origin_to_all (origin, - 0, - 0, - origin_notify, - pp_msg); -} - - -static void -origin_message (void *cls, - const struct GNUNET_MULTICAST_MessageHeader *msg) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin message msg\n"); -} - - -static void -multicast_disconnect (void *cls, - void *op_result) -{ - -} - - -static void * -multicast_connect (void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct MulticastPeerContext *multicast_peer = cls; - struct GNUNET_MessageHeader *join_msg; - char data[64]; - - if (0 == multicast_peer->peer) - { - group_key = GNUNET_CRYPTO_eddsa_key_create (); - GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key); - - GNUNET_CRYPTO_hash (&group_pub_key, sizeof (group_pub_key), &group_pub_key_hash); - origin = GNUNET_MULTICAST_origin_start (cfg, - group_key, - 0, - origin_join_request, - origin_replay_frag, - origin_replay_msg, - origin_request, - origin_message, - cls); - if (NULL == origin) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Peer #%u could not create a multicast group", - multicast_peer->peer); - return NULL; - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Peer #%u connected as origin to group %s\n", - multicast_peer->peer, - GNUNET_h2s (&group_pub_key_hash)); - return origin; - } - else - { - multicast_peer->key = GNUNET_CRYPTO_ecdsa_key_create (); - - sprintf(data, "Hi, I am peer #%u (%s). Can I enter?", - multicast_peer->peer, - GNUNET_i2s (multicast_peers[multicast_peer->peer]->id)); - uint8_t data_size = strlen (data) + 1; - join_msg = GNUNET_malloc (sizeof (join_msg) + data_size); - join_msg->size = htons (sizeof (join_msg) + data_size); - join_msg->type = htons (123); - GNUNET_memcpy (&join_msg[1], data, data_size); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Peer #%u (%s) tries to join multicast group %s\n", - multicast_peer->peer, - GNUNET_i2s (multicast_peers[multicast_peer->peer]->id), - GNUNET_h2s (&group_pub_key_hash)); - - members[multicast_peer->peer] = - GNUNET_MULTICAST_member_join (cfg, - &group_pub_key, - multicast_peer->key, - multicast_peers[0]->id, - 0, - NULL, - join_msg, /* join message */ - member_join_request, - member_join_decision, - member_replay_frag, - member_replay_msg, - member_message, - cls); - return members[multicast_peer->peer]; - } -} - - -static void -peer_information_cb (void *cls, - struct GNUNET_TESTBED_Operation *operation, - const struct GNUNET_TESTBED_PeerInformation *pinfo, - const char *emsg) -{ - struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls; - - if (NULL == pinfo) { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "got no peer information\n"); - result = GNUNET_SYSERR; - GNUNET_SCHEDULER_shutdown (); - } - - multicast_peers[mc_peer->peer]->id = pinfo->result.id; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Got peer information of %s (%s)\n", - (0 == mc_peer->peer)? "origin" : "member", - GNUNET_i2s (pinfo->result.id)); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Create peer #%u (%s)\n", - mc_peer->peer, - GNUNET_i2s (multicast_peers[mc_peer->peer]->id)); - - if (0 != mc_peer->peer) - { - /* connect to multicast service of members */ - op[mc_peer->peer] = - GNUNET_TESTBED_service_connect (/* Closure for operation */ - NULL, - /* The peer whose service to connect to */ - peers[mc_peer->peer], - /* The name of the service */ - "multicast", - /* called after a handle to service is opened */ - service_connect, - /* closure for the above callback */ - cls, - /* called when opening the service connection */ - multicast_connect, - /* called when closing the service connection */ - multicast_disconnect, - /* closure for the above two callbacks */ - cls); - } -} - - -static void -service_connect (void *cls, - struct GNUNET_TESTBED_Operation *op, - void *ca_result, - const char *emsg) -{ - struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls; - - if (NULL == ca_result) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Connection adapter not created for peer #%u (%s)\n", - mc_peer->peer, - GNUNET_i2s (multicast_peers[mc_peer->peer]->id)); - - result = GNUNET_SYSERR; - GNUNET_SCHEDULER_shutdown(); - } - - if (0 == mc_peer->peer) - { - // Get GNUnet identity of members - for (int i = 0; ipeer = i; - multicast_peers[i]->test_ok = GNUNET_NO; - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Create origin peer\n"); - op[0] = - GNUNET_TESTBED_service_connect (/* Closure for operation */ - NULL, - /* The peer whose service to connect to */ - peers[0], - /* The name of the service */ - "multicast", - /* called after a handle to service is opened */ - service_connect, - /* closure for the above callback */ - multicast_peers[0], - /* called when opening the service connection */ - multicast_connect, - /* called when closing the service connection */ - multicast_disconnect, - /* closure for the above two callbacks */ - multicast_peers[0]); - /* Schedule a new task on shutdown */ - GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); - /* Schedule the shutdown task with a delay of a few Seconds */ - timeout_tid = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 400), - &timeout_task, - NULL); -} - - -int -main (int argc, char *argv[]) -{ - int ret; - char const *config_file; - - if (strstr (argv[0], "_line") != NULL) - { - config_file = "test_multicast_line.conf"; - } - else if (strstr(argv[0], "_star") != NULL) - { - config_file = "test_multicast_star.conf"; - } - else - { - config_file = "test_multicast_star.conf"; - } - - result = GNUNET_SYSERR; - ret = - GNUNET_TESTBED_test_run ("test-multicast-multipeer", - config_file, - /* number of peers to start */ - PEERS_REQUESTED, - /* Event mask - set to 0 for no event notifications */ - 0LL, - /* Controller event callback */ - NULL, - /* Closure for controller event callback */ - NULL, - /* called when testbed setup is complete */ - testbed_master, - /* Closure for the test_master callback */ - NULL); - if ( (GNUNET_OK != ret) || (GNUNET_OK != result) ) - return 1; - return 0; -} - -/* end of test_multicast_multipeer.c */ diff --git a/src/multicast/test_multicast_star.conf b/src/multicast/test_multicast_star.conf deleted file mode 100644 index 516c0e302..000000000 --- a/src/multicast/test_multicast_star.conf +++ /dev/null @@ -1,64 +0,0 @@ -[testbed] -HOSTNAME = localhost -OVERLAY_TOPOLOGY = STAR - -[arm] -GLOBAL_POSTFIX=-L ERROR - -[multicast] -#PREFIX = tmux new-window gdb -x ./cmd.gdb --args -#PREFIX = valgrind --leak-check=full -UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock - -[vpn] -START_ON_DEMAND = NO - -[peerinfo] -# Do not use shipped gnunet HELLOs -USE_INCLUDED_HELLOS = NO - -# Option to disable all disk IO; only useful for testbed runs -# (large-scale experiments); disables persistence of HELLOs! -NO_IO = YES - -[cadet] -ID_ANNOUNCE_TIME = 5 s - -[hostlist] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[nat] -ENABLE_UPNP = NO - -[fs] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[vpn] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[revocation] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[gns] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[namestore] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[namecache] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[topology] -IMMEDIATE_START = NO -START_ON_DEMAND = NO - -[nse] -WORKBITS = 0 - diff --git a/src/psyc/.gitignore b/src/psyc/.gitignore deleted file mode 100644 index 14a175367..000000000 --- a/src/psyc/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -gnunet-service-psyc -test_psyc diff --git a/src/psyc/Makefile.am b/src/psyc/Makefile.am deleted file mode 100644 index 511e3e3f7..000000000 --- a/src/psyc/Makefile.am +++ /dev/null @@ -1,77 +0,0 @@ -# This Makefile.am is in the public domain -AM_CPPFLAGS = -I$(top_srcdir)/src/include - -pkgcfgdir= $(pkgdatadir)/config.d/ - -libexecdir= $(pkglibdir)/libexec/ - -pkgcfg_DATA = \ - psyc.conf - - -if MINGW - WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -endif - -if USE_COVERAGE - AM_CFLAGS = --coverage -O0 - XLIB = -lgcov -endif - -lib_LTLIBRARIES = libgnunetpsyc.la - -libgnunetpsyc_la_SOURCES = \ - psyc_api.c psyc.h -libgnunetpsyc_la_LIBADD = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/psycutil/libgnunetpsycutil.la \ - $(GN_LIBINTL) $(XLIB) -libgnunetpsyc_la_LDFLAGS = \ - $(GN_LIB_LDFLAGS) $(WINFLAGS) \ - -version-info 0:0:0 - -bin_PROGRAMS = - -libexec_PROGRAMS = \ - gnunet-service-psyc - -gnunet_service_psyc_SOURCES = \ - gnunet-service-psyc.c -gnunet_service_psyc_LDADD = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(top_builddir)/src/multicast/libgnunetmulticast.la \ - $(top_builddir)/src/psycstore/libgnunetpsycstore.la \ - $(top_builddir)/src/psycutil/libgnunetpsycutil.la \ - $(GN_LIBINTL) -gnunet_service_psyc_CFLAGS = $(AM_CFLAGS) - - -if HAVE_TESTING -check_PROGRAMS = \ - test_psyc -# test_psyc2 -endif - -if ENABLE_TEST_RUN -AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; -TESTS = $(check_PROGRAMS) -endif - -test_psyc_SOURCES = \ - test_psyc.c -test_psyc_LDADD = \ - libgnunetpsyc.la \ - $(top_builddir)/src/psycutil/libgnunetpsycutil.la \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/util/libgnunetutil.la -#test_psyc2_SOURCES = \ -# test_psyc2.c -#test_psyc2_LDADD = \ -# libgnunetpsyc.la \ -# $(top_builddir)/src/psycutil/libgnunetpsycutil.la \ -# $(top_builddir)/src/testbed/libgnunettestbed.la \ -# $(top_builddir)/src/util/libgnunetutil.la - -EXTRA_DIST = \ - test_psyc.conf diff --git a/src/psyc/gnunet-service-psyc.c b/src/psyc/gnunet-service-psyc.c deleted file mode 100644 index 6f2f7a999..000000000 --- a/src/psyc/gnunet-service-psyc.c +++ /dev/null @@ -1,2860 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file psyc/gnunet-service-psyc.c - * @brief PSYC service - * @author Gabor X Toth - */ - -#include - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_constants.h" -#include "gnunet_protocols.h" -#include "gnunet_statistics_service.h" -#include "gnunet_multicast_service.h" -#include "gnunet_psycstore_service.h" -#include "gnunet_psyc_service.h" -#include "gnunet_psyc_util_lib.h" -#include "psyc.h" - - -/** - * Handle to our current configuration. - */ -static const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * Service handle. - */ -static struct GNUNET_SERVICE_Handle *service; - -/** - * Handle to the statistics service. - */ -static struct GNUNET_STATISTICS_Handle *stats; - -/** - * Handle to the PSYCstore. - */ -static struct GNUNET_PSYCSTORE_Handle *store; - -/** - * All connected masters. - * Channel's pub_key_hash -> struct Master - */ -static struct GNUNET_CONTAINER_MultiHashMap *masters; - -/** - * All connected slaves. - * Channel's pub_key_hash -> struct Slave - */ -static struct GNUNET_CONTAINER_MultiHashMap *slaves; - -/** - * Connected slaves per channel. - * Channel's pub_key_hash -> Slave's pub_key -> struct Slave - */ -static struct GNUNET_CONTAINER_MultiHashMap *channel_slaves; - - -/** - * Message in the transmission queue. - */ -struct TransmitMessage -{ - struct TransmitMessage *prev; - struct TransmitMessage *next; - - struct GNUNET_SERVICE_Client *client; - - /** - * ID assigned to the message. - */ - uint64_t id; - - /** - * Size of message. - */ - uint16_t size; - - /** - * Type of first message part. - */ - uint16_t first_ptype; - - /** - * Type of last message part. - */ - uint16_t last_ptype; - - /* Followed by message */ -}; - - -/** - * Cache for received message fragments. - * Message fragments are only sent to clients after all modifiers arrived. - * - * chan_key -> MultiHashMap chan_msgs - */ -static struct GNUNET_CONTAINER_MultiHashMap *recv_cache; - - -/** - * Entry in the chan_msgs hashmap of @a recv_cache: - * fragment_id -> RecvCacheEntry - */ -struct RecvCacheEntry -{ - struct GNUNET_MULTICAST_MessageHeader *mmsg; - uint16_t ref_count; -}; - - -/** - * Entry in the @a recv_frags hash map of a @a Channel. - * message_id -> FragmentQueue - */ -struct FragmentQueue -{ - /** - * Fragment IDs stored in @a recv_cache. - */ - struct GNUNET_CONTAINER_Heap *fragments; - - /** - * Total size of received fragments. - */ - uint64_t size; - - /** - * Total size of received header fragments (METHOD & MODIFIERs) - */ - uint64_t header_size; - - /** - * The @a state_delta field from struct GNUNET_PSYC_MessageMethod. - */ - uint64_t state_delta; - - /** - * The @a flags field from struct GNUNET_PSYC_MessageMethod. - */ - uint32_t flags; - - /** - * Receive state of message. - * - * @see MessageFragmentState - */ - uint8_t state; - - /** - * Whether the state is already modified in PSYCstore. - */ - uint8_t state_is_modified; - - /** - * Is the message queued for delivery to the client? - * i.e. added to the recv_msgs queue - */ - uint8_t is_queued; -}; - - -/** - * List of connected clients. - */ -struct ClientList -{ - struct ClientList *prev; - struct ClientList *next; - - struct GNUNET_SERVICE_Client *client; -}; - - -struct Operation -{ - struct Operation *prev; - struct Operation *next; - - struct GNUNET_SERVICE_Client *client; - struct Channel *channel; - uint64_t op_id; - uint32_t flags; -}; - - -/** - * Common part of the client context for both a channel master and slave. - */ -struct Channel -{ - struct ClientList *clients_head; - struct ClientList *clients_tail; - - struct Operation *op_head; - struct Operation *op_tail; - - struct TransmitMessage *tmit_head; - struct TransmitMessage *tmit_tail; - - /** - * Current PSYCstore operation. - */ - struct GNUNET_PSYCSTORE_OperationHandle *store_op; - - /** - * Received fragments not yet sent to the client. - * message_id -> FragmentQueue - */ - struct GNUNET_CONTAINER_MultiHashMap *recv_frags; - - /** - * Received message IDs not yet sent to the client. - */ - struct GNUNET_CONTAINER_Heap *recv_msgs; - - /** - * Public key of the channel. - */ - struct GNUNET_CRYPTO_EddsaPublicKey pub_key; - - /** - * Hash of @a pub_key. - */ - struct GNUNET_HashCode pub_key_hash; - - /** - * Last message ID sent to the client. - * 0 if there is no such message. - */ - uint64_t max_message_id; - - /** - * ID of the last stateful message, where the state operations has been - * processed and saved to PSYCstore and which has been sent to the client. - * 0 if there is no such message. - */ - uint64_t max_state_message_id; - - /** - * Expected value size for the modifier being received from the PSYC service. - */ - uint32_t tmit_mod_value_size_expected; - - /** - * Actual value size for the modifier being received from the PSYC service. - */ - uint32_t tmit_mod_value_size; - - /** - * Is this channel ready to receive messages from client? - * #GNUNET_YES or #GNUNET_NO - */ - uint8_t is_ready; - - /** - * Is the client disconnected? - * #GNUNET_YES or #GNUNET_NO - */ - uint8_t is_disconnecting; - - /** - * Is this a channel master (#GNUNET_YES), or slave (#GNUNET_NO)? - */ - uint8_t is_master; - - union { - struct Master *master; - struct Slave *slave; - }; -}; - - -/** - * Client context for a channel master. - */ -struct Master -{ - /** - * Channel struct common for Master and Slave - */ - struct Channel channel; - - /** - * Private key of the channel. - */ - struct GNUNET_CRYPTO_EddsaPrivateKey priv_key; - - /** - * Handle for the multicast origin. - */ - struct GNUNET_MULTICAST_Origin *origin; - - /** - * Transmit handle for multicast. - */ - struct GNUNET_MULTICAST_OriginTransmitHandle *tmit_handle; - - /** - * Incoming join requests from multicast. - * member_pub_key -> struct GNUNET_MULTICAST_JoinHandle * - */ - struct GNUNET_CONTAINER_MultiHashMap *join_reqs; - - /** - * Last message ID transmitted to this channel. - * - * Incremented before sending a message, thus the message_id in messages sent - * starts from 1. - */ - uint64_t max_message_id; - - /** - * ID of the last message with state operations transmitted to the channel. - * 0 if there is no such message. - */ - uint64_t max_state_message_id; - - /** - * Maximum group generation transmitted to the channel. - */ - uint64_t max_group_generation; - - /** - * @see enum GNUNET_PSYC_Policy - */ - enum GNUNET_PSYC_Policy policy; -}; - - -/** - * Client context for a channel slave. - */ -struct Slave -{ - /** - * Channel struct common for Master and Slave - */ - struct Channel channel; - - /** - * Private key of the slave. - */ - struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key; - - /** - * Public key of the slave. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; - - /** - * Hash of @a pub_key. - */ - struct GNUNET_HashCode pub_key_hash; - - /** - * Handle for the multicast member. - */ - struct GNUNET_MULTICAST_Member *member; - - /** - * Transmit handle for multicast. - */ - struct GNUNET_MULTICAST_MemberTransmitHandle *tmit_handle; - - /** - * Peer identity of the origin. - */ - struct GNUNET_PeerIdentity origin; - - /** - * Number of items in @a relays. - */ - uint32_t relay_count; - - /** - * Relays that multicast can use to connect. - */ - struct GNUNET_PeerIdentity *relays; - - /** - * Join request to be transmitted to the master on join. - */ - struct GNUNET_PSYC_Message *join_msg; - - /** - * Join decision received from multicast. - */ - struct GNUNET_PSYC_JoinDecisionMessage *join_dcsn; - - /** - * Maximum request ID for this channel. - */ - uint64_t max_request_id; - - /** - * Join flags. - */ - enum GNUNET_PSYC_SlaveJoinFlags join_flags; -}; - - -/** - * Client context. - */ -struct Client { - struct GNUNET_SERVICE_Client *client; - struct Channel *channel; -}; - - -struct ReplayRequestKey -{ - uint64_t fragment_id; - uint64_t message_id; - uint64_t fragment_offset; - uint64_t flags; -}; - - -static void -transmit_message (struct Channel *chn); - -static uint64_t -message_queue_run (struct Channel *chn); - -static uint64_t -message_queue_drop (struct Channel *chn); - - -static void -schedule_transmit_message (void *cls) -{ - struct Channel *chn = cls; - - transmit_message (chn); -} - - -/** - * Task run during shutdown. - * - * @param cls unused - */ -static void -shutdown_task (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "shutting down...\n"); - GNUNET_PSYCSTORE_disconnect (store); - if (NULL != stats) - { - GNUNET_STATISTICS_destroy (stats, GNUNET_YES); - stats = NULL; - } -} - - -static struct Operation * -op_add (struct Channel *chn, struct GNUNET_SERVICE_Client *client, - uint64_t op_id, uint32_t flags) -{ - struct Operation *op = GNUNET_malloc (sizeof (*op)); - op->client = client; - op->channel = chn; - op->op_id = op_id; - op->flags = flags; - GNUNET_CONTAINER_DLL_insert (chn->op_head, chn->op_tail, op); - return op; -} - - -static void -op_remove (struct Operation *op) -{ - GNUNET_CONTAINER_DLL_remove (op->channel->op_head, op->channel->op_tail, op); - GNUNET_free (op); -} - - -/** - * Clean up master data structures after a client disconnected. - */ -static void -cleanup_master (struct Master *mst) -{ - struct Channel *chn = &mst->channel; - - GNUNET_CONTAINER_multihashmap_destroy (mst->join_reqs); - GNUNET_CONTAINER_multihashmap_remove (masters, &chn->pub_key_hash, mst); -} - - -/** - * Clean up slave data structures after a client disconnected. - */ -static void -cleanup_slave (struct Slave *slv) -{ - struct Channel *chn = &slv->channel; - struct GNUNET_CONTAINER_MultiHashMap * - chn_slv = GNUNET_CONTAINER_multihashmap_get (channel_slaves, - &chn->pub_key_hash); - GNUNET_assert (NULL != chn_slv); - GNUNET_CONTAINER_multihashmap_remove (chn_slv, &slv->pub_key_hash, slv); - - if (0 == GNUNET_CONTAINER_multihashmap_size (chn_slv)) - { - GNUNET_CONTAINER_multihashmap_remove (channel_slaves, &chn->pub_key_hash, - chn_slv); - GNUNET_CONTAINER_multihashmap_destroy (chn_slv); - } - GNUNET_CONTAINER_multihashmap_remove (slaves, &chn->pub_key_hash, slv); - - if (NULL != slv->join_msg) - { - GNUNET_free (slv->join_msg); - slv->join_msg = NULL; - } - if (NULL != slv->relays) - { - GNUNET_free (slv->relays); - slv->relays = NULL; - } - GNUNET_CONTAINER_multihashmap_remove (slaves, &chn->pub_key_hash, slv); -} - - -/** - * Clean up channel data structures after a client disconnected. - */ -static void -cleanup_channel (struct Channel *chn) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Cleaning up channel %s. master? %u\n", - chn, - GNUNET_h2s (&chn->pub_key_hash), - chn->is_master); - message_queue_drop (chn); - GNUNET_CONTAINER_multihashmap_destroy (chn->recv_frags); - chn->recv_frags = NULL; - - if (NULL != chn->store_op) - { - GNUNET_PSYCSTORE_operation_cancel (chn->store_op); - chn->store_op = NULL; - } - - (GNUNET_YES == chn->is_master) - ? cleanup_master (chn->master) - : cleanup_slave (chn->slave); - GNUNET_free (chn); -} - - -/** - * Called whenever a client is disconnected. - * Frees our resources associated with that client. - * - * @param cls closure - * @param client identification of the client - * @param app_ctx must match @a client - */ -static void -client_notify_disconnect (void *cls, - struct GNUNET_SERVICE_Client *client, - void *app_ctx) -{ - struct Client *c = app_ctx; - struct Channel *chn = c->channel; - GNUNET_free (c); - - if (NULL == chn) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p User context is NULL in client_notify_disconnect ()\n", - chn); - GNUNET_break (0); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Client %p (%s) disconnected from channel %s\n", - chn, - client, - (GNUNET_YES == chn->is_master) ? "master" : "slave", - GNUNET_h2s (&chn->pub_key_hash)); - - struct ClientList *cli = chn->clients_head; - while (NULL != cli) - { - if (cli->client == client) - { - GNUNET_CONTAINER_DLL_remove (chn->clients_head, chn->clients_tail, cli); - GNUNET_free (cli); - break; - } - cli = cli->next; - } - - struct Operation *op = chn->op_head; - while (NULL != op) - { - if (op->client == client) - { - op->client = NULL; - break; - } - op = op->next; - } - - if (NULL == chn->clients_head) - { /* Last client disconnected. */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Last client (%s) disconnected from channel %s\n", - chn, - (GNUNET_YES == chn->is_master) ? "master" : "slave", - GNUNET_h2s (&chn->pub_key_hash)); - chn->is_disconnecting = GNUNET_YES; - cleanup_channel (chn); - } -} - - -/** - * A new client connected. - * - * @param cls NULL - * @param client client to add - * @param mq message queue for @a client - * @return @a client - */ -static void * -client_notify_connect (void *cls, - struct GNUNET_SERVICE_Client *client, - struct GNUNET_MQ_Handle *mq) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client connected: %p\n", client); - - struct Client *c = GNUNET_malloc (sizeof (*c)); - c->client = client; - - return c; -} - - -/** - * Send message to all clients connected to the channel. - */ -static void -client_send_msg (const struct Channel *chn, - const struct GNUNET_MessageHeader *msg) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending message to clients of channel %p.\n", - chn); - - struct ClientList *cli = chn->clients_head; - while (NULL != cli) - { - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_copy (msg); - - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (cli->client), - env); - cli = cli->next; - } -} - - -/** - * Send a result code back to the client. - * - * @param client - * Client that should receive the result code. - * @param result_code - * Code to transmit. - * @param op_id - * Operation ID in network byte order. - * @param data - * Data payload or NULL. - * @param data_size - * Size of @a data. - */ -static void -client_send_result (struct GNUNET_SERVICE_Client *client, uint64_t op_id, - int64_t result_code, const void *data, uint16_t data_size) -{ - struct GNUNET_OperationResultMessage *res; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (res, - data_size, - GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE); - res->result_code = GNUNET_htonll (result_code); - res->op_id = op_id; - if (0 < data_size) - GNUNET_memcpy (&res[1], data, data_size); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Sending result to client for OP ID %" PRIu64 ": %" PRId64 " (size: %u)\n", - client, - GNUNET_ntohll (op_id), - result_code, - data_size); - - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env); -} - - -/** - * Closure for join_mem_test_cb() - */ -struct JoinMemTestClosure -{ - struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; - struct Channel *channel; - struct GNUNET_MULTICAST_JoinHandle *join_handle; - struct GNUNET_PSYC_JoinRequestMessage *join_msg; -}; - - -/** - * Membership test result callback used for join requests. - */ -static void -join_mem_test_cb (void *cls, int64_t result, - const char *err_msg, uint16_t err_msg_size) -{ - struct JoinMemTestClosure *jcls = cls; - - if (GNUNET_NO == result && GNUNET_YES == jcls->channel->is_master) - { /* Pass on join request to client if this is a master channel */ - struct Master *mst = jcls->channel->master; - struct GNUNET_HashCode slave_pub_hash; - GNUNET_CRYPTO_hash (&jcls->slave_pub_key, sizeof (jcls->slave_pub_key), - &slave_pub_hash); - GNUNET_CONTAINER_multihashmap_put (mst->join_reqs, &slave_pub_hash, jcls->join_handle, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - client_send_msg (jcls->channel, &jcls->join_msg->header); - } - else - { - if (GNUNET_SYSERR == result) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not perform membership test (%.*s)\n", - err_msg_size, err_msg); - } - // FIXME: add relays - GNUNET_MULTICAST_join_decision (jcls->join_handle, result, 0, NULL, NULL); - } - GNUNET_free (jcls->join_msg); - GNUNET_free (jcls); -} - - -/** - * Incoming join request from multicast. - */ -static void -mcast_recv_join_request (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key, - const struct GNUNET_MessageHeader *join_msg, - struct GNUNET_MULTICAST_JoinHandle *jh) -{ - struct Channel *chn = cls; - uint16_t join_msg_size = 0; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Got join request.\n", - chn); - if (NULL != join_msg) - { - if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE == ntohs (join_msg->type)) - { - join_msg_size = ntohs (join_msg->size); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "%p Got join message with invalid type %u.\n", - chn, - ntohs (join_msg->type)); - } - } - - struct GNUNET_PSYC_JoinRequestMessage * - req = GNUNET_malloc (sizeof (*req) + join_msg_size); - req->header.size = htons (sizeof (*req) + join_msg_size); - req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST); - req->slave_pub_key = *slave_pub_key; - if (0 < join_msg_size) - GNUNET_memcpy (&req[1], join_msg, join_msg_size); - - struct JoinMemTestClosure *jcls = GNUNET_malloc (sizeof (*jcls)); - jcls->slave_pub_key = *slave_pub_key; - jcls->channel = chn; - jcls->join_handle = jh; - jcls->join_msg = req; - - GNUNET_PSYCSTORE_membership_test (store, &chn->pub_key, slave_pub_key, - chn->max_message_id, 0, - &join_mem_test_cb, jcls); -} - - -/** - * Join decision received from multicast. - */ -static void -mcast_recv_join_decision (void *cls, int is_admitted, - const struct GNUNET_PeerIdentity *peer, - uint16_t relay_count, - const struct GNUNET_PeerIdentity *relays, - const struct GNUNET_MessageHeader *join_resp) -{ - struct Slave *slv = cls; - struct Channel *chn = &slv->channel; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Got join decision: %d\n", - slv, - is_admitted); - if (GNUNET_YES == chn->is_ready) - { - /* Already admitted */ - return; - } - - uint16_t join_resp_size = (NULL != join_resp) ? ntohs (join_resp->size) : 0; - struct GNUNET_PSYC_JoinDecisionMessage * - dcsn = slv->join_dcsn = GNUNET_malloc (sizeof (*dcsn) + join_resp_size); - dcsn->header.size = htons (sizeof (*dcsn) + join_resp_size); - dcsn->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION); - dcsn->is_admitted = htonl (is_admitted); - if (0 < join_resp_size) - GNUNET_memcpy (&dcsn[1], join_resp, join_resp_size); - - client_send_msg (chn, &dcsn->header); - - if (GNUNET_YES == is_admitted - && ! (GNUNET_PSYC_SLAVE_JOIN_LOCAL & slv->join_flags)) - { - chn->is_ready = GNUNET_YES; - } -} - - -static int -store_recv_fragment_replay (void *cls, - struct GNUNET_MULTICAST_MessageHeader *msg, - enum GNUNET_PSYCSTORE_MessageFlags flags) -{ - struct GNUNET_MULTICAST_ReplayHandle *rh = cls; - - GNUNET_MULTICAST_replay_response (rh, &msg->header, GNUNET_MULTICAST_REC_OK); - return GNUNET_YES; -} - - -/** - * Received result of GNUNET_PSYCSTORE_fragment_get() for multicast replay. - */ -static void -store_recv_fragment_replay_result (void *cls, - int64_t result, - const char *err_msg, - uint16_t err_msg_size) -{ - struct GNUNET_MULTICAST_ReplayHandle *rh = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Fragment replay: PSYCSTORE returned %" PRId64 " (%.*s)\n", - rh, - result, - err_msg_size, - err_msg); - switch (result) - { - case GNUNET_YES: - break; - - case GNUNET_NO: - GNUNET_MULTICAST_replay_response (rh, NULL, - GNUNET_MULTICAST_REC_NOT_FOUND); - return; - - case GNUNET_PSYCSTORE_MEMBERSHIP_TEST_FAILED: - GNUNET_MULTICAST_replay_response (rh, NULL, - GNUNET_MULTICAST_REC_ACCESS_DENIED); - return; - - case GNUNET_SYSERR: - GNUNET_MULTICAST_replay_response (rh, NULL, - GNUNET_MULTICAST_REC_INTERNAL_ERROR); - return; - } - /* GNUNET_MULTICAST_replay_response frees 'rh' when passed - * an error code, so it must be ensured no further processing - * is attempted on 'rh'. Maybe this should be refactored as - * it doesn't look very intuitive. --lynX - */ - GNUNET_MULTICAST_replay_response_end (rh); -} - - -/** - * Incoming fragment replay request from multicast. - */ -static void -mcast_recv_replay_fragment (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key, - uint64_t fragment_id, uint64_t flags, - struct GNUNET_MULTICAST_ReplayHandle *rh) - -{ - struct Channel *chn = cls; - GNUNET_PSYCSTORE_fragment_get (store, &chn->pub_key, slave_pub_key, - fragment_id, fragment_id, - &store_recv_fragment_replay, - &store_recv_fragment_replay_result, rh); -} - - -/** - * Incoming message replay request from multicast. - */ -static void -mcast_recv_replay_message (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key, - uint64_t message_id, - uint64_t fragment_offset, - uint64_t flags, - struct GNUNET_MULTICAST_ReplayHandle *rh) -{ - struct Channel *chn = cls; - GNUNET_PSYCSTORE_message_get (store, &chn->pub_key, slave_pub_key, - message_id, message_id, 1, NULL, - &store_recv_fragment_replay, - &store_recv_fragment_replay_result, rh); -} - - -/** - * Convert an uint64_t in network byte order to a HashCode - * that can be used as key in a MultiHashMap - */ -static inline void -hash_key_from_nll (struct GNUNET_HashCode *key, uint64_t n) -{ - /* use little-endian order, as idx_of MultiHashMap casts key to unsigned int */ - /* TODO: use built-in byte swap functions if available */ - - n = ((n << 8) & 0xFF00FF00FF00FF00ULL) | ((n >> 8) & 0x00FF00FF00FF00FFULL); - n = ((n << 16) & 0xFFFF0000FFFF0000ULL) | ((n >> 16) & 0x0000FFFF0000FFFFULL); - - *key = (struct GNUNET_HashCode) {}; - *((uint64_t *) key) - = (n << 32) | (n >> 32); -} - - -/** - * Convert an uint64_t in host byte order to a HashCode - * that can be used as key in a MultiHashMap - */ -static inline void -hash_key_from_hll (struct GNUNET_HashCode *key, uint64_t n) -{ -#if __BYTE_ORDER == __BIG_ENDIAN - hash_key_from_nll (key, n); -#elif __BYTE_ORDER == __LITTLE_ENDIAN - *key = (struct GNUNET_HashCode) {}; - *((uint64_t *) key) = n; -#else - #error byteorder undefined -#endif -} - - -/** - * Initialize PSYC message header. - */ -static inline void -psyc_msg_init (struct GNUNET_PSYC_MessageHeader *pmsg, - const struct GNUNET_MULTICAST_MessageHeader *mmsg, uint32_t flags) -{ - uint16_t size = ntohs (mmsg->header.size); - uint16_t psize = sizeof (*pmsg) + size - sizeof (*mmsg); - - pmsg->header.size = htons (psize); - pmsg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); - pmsg->message_id = mmsg->message_id; - pmsg->fragment_offset = mmsg->fragment_offset; - pmsg->flags = htonl (flags); - - GNUNET_memcpy (&pmsg[1], &mmsg[1], size - sizeof (*mmsg)); -} - - -/** - * Create a new PSYC message from a multicast message for sending it to clients. - */ -static inline struct GNUNET_PSYC_MessageHeader * -psyc_msg_new (const struct GNUNET_MULTICAST_MessageHeader *mmsg, uint32_t flags) -{ - struct GNUNET_PSYC_MessageHeader *pmsg; - uint16_t size = ntohs (mmsg->header.size); - uint16_t psize = sizeof (*pmsg) + size - sizeof (*mmsg); - - pmsg = GNUNET_malloc (psize); - psyc_msg_init (pmsg, mmsg, flags); - return pmsg; -} - - -/** - * Send multicast message to all clients connected to the channel. - */ -static void -client_send_mcast_msg (struct Channel *chn, - const struct GNUNET_MULTICAST_MessageHeader *mmsg, - uint32_t flags) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Sending multicast message to client. fragment_id: %" PRIu64 ", message_id: %" PRIu64 "\n", - chn, - GNUNET_ntohll (mmsg->fragment_id), - GNUNET_ntohll (mmsg->message_id)); - - struct GNUNET_PSYC_MessageHeader * - pmsg = GNUNET_PSYC_message_header_create (mmsg, flags); - client_send_msg (chn, &pmsg->header); - GNUNET_free (pmsg); -} - - -/** - * Send multicast request to all clients connected to the channel. - */ -static void -client_send_mcast_req (struct Master *mst, - const struct GNUNET_MULTICAST_RequestHeader *req) -{ - struct Channel *chn = &mst->channel; - - struct GNUNET_PSYC_MessageHeader *pmsg; - uint16_t size = ntohs (req->header.size); - uint16_t psize = sizeof (*pmsg) + size - sizeof (*req); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Sending multicast request to client. fragment_id: %" PRIu64 ", message_id: %" PRIu64 "\n", - chn, - GNUNET_ntohll (req->fragment_id), - GNUNET_ntohll (req->request_id)); - - pmsg = GNUNET_malloc (psize); - pmsg->header.size = htons (psize); - pmsg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); - pmsg->message_id = req->request_id; - pmsg->fragment_offset = req->fragment_offset; - pmsg->flags = htonl (GNUNET_PSYC_MESSAGE_REQUEST); - pmsg->slave_pub_key = req->member_pub_key; - GNUNET_memcpy (&pmsg[1], &req[1], size - sizeof (*req)); - - client_send_msg (chn, &pmsg->header); - - /* FIXME: save req to PSYCstore so that it can be resent later to clients */ - - GNUNET_free (pmsg); -} - - -/** - * Insert a multicast message fragment into the queue belonging to the message. - * - * @param chn Channel. - * @param mmsg Multicast message fragment. - * @param msg_id_hash Message ID of @a mmsg in a struct GNUNET_HashCode. - * @param first_ptype First PSYC message part type in @a mmsg. - * @param last_ptype Last PSYC message part type in @a mmsg. - */ -static void -fragment_queue_insert (struct Channel *chn, - const struct GNUNET_MULTICAST_MessageHeader *mmsg, - uint16_t first_ptype, uint16_t last_ptype) -{ - const uint16_t size = ntohs (mmsg->header.size); - const uint64_t frag_offset = GNUNET_ntohll (mmsg->fragment_offset); - struct GNUNET_CONTAINER_MultiHashMap - *chan_msgs = GNUNET_CONTAINER_multihashmap_get (recv_cache, - &chn->pub_key_hash); - - struct GNUNET_HashCode msg_id_hash; - hash_key_from_nll (&msg_id_hash, mmsg->message_id); - - struct FragmentQueue - *fragq = GNUNET_CONTAINER_multihashmap_get (chn->recv_frags, &msg_id_hash); - - if (NULL == fragq) - { - fragq = GNUNET_malloc (sizeof (*fragq)); - fragq->state = MSG_FRAG_STATE_HEADER; - fragq->fragments - = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); - - GNUNET_CONTAINER_multihashmap_put (chn->recv_frags, &msg_id_hash, fragq, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - - if (NULL == chan_msgs) - { - chan_msgs = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - GNUNET_CONTAINER_multihashmap_put (recv_cache, &chn->pub_key_hash, chan_msgs, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - } - } - - struct GNUNET_HashCode frag_id_hash; - hash_key_from_nll (&frag_id_hash, mmsg->fragment_id); - struct RecvCacheEntry - *cache_entry = GNUNET_CONTAINER_multihashmap_get (chan_msgs, &frag_id_hash); - if (NULL == cache_entry) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Adding message fragment to cache. message_id: %" PRIu64 ", fragment_id: %" PRIu64 "\n", - chn, - GNUNET_ntohll (mmsg->message_id), - GNUNET_ntohll (mmsg->fragment_id)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p header_size: %" PRIu64 " + %u\n", - chn, - fragq->header_size, - size); - cache_entry = GNUNET_malloc (sizeof (*cache_entry)); - cache_entry->ref_count = 1; - cache_entry->mmsg = GNUNET_malloc (size); - GNUNET_memcpy (cache_entry->mmsg, mmsg, size); - GNUNET_CONTAINER_multihashmap_put (chan_msgs, &frag_id_hash, cache_entry, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - } - else - { - cache_entry->ref_count++; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Message fragment is already in cache. message_id: %" PRIu64 ", fragment_id: %" PRIu64 ", ref_count: %u\n", - chn, - GNUNET_ntohll (mmsg->message_id), - GNUNET_ntohll (mmsg->fragment_id), - cache_entry->ref_count); - } - - if (MSG_FRAG_STATE_HEADER == fragq->state) - { - if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == first_ptype) - { - struct GNUNET_PSYC_MessageMethod * - pmeth = (struct GNUNET_PSYC_MessageMethod *) &mmsg[1]; - fragq->state_delta = GNUNET_ntohll (pmeth->state_delta); - fragq->flags = ntohl (pmeth->flags); - } - - if (last_ptype < GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA) - { - fragq->header_size += size; - } - else if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == first_ptype - || frag_offset == fragq->header_size) - { /* header is now complete */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Header of message %" PRIu64 " is complete.\n", - chn, - GNUNET_ntohll (mmsg->message_id)); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Adding message %" PRIu64 " to queue.\n", - chn, - GNUNET_ntohll (mmsg->message_id)); - fragq->state = MSG_FRAG_STATE_DATA; - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Header of message %" PRIu64 " is NOT complete yet: %" PRIu64 " != %" PRIu64 "\n", - chn, - GNUNET_ntohll (mmsg->message_id), - frag_offset, - fragq->header_size); - } - } - - switch (last_ptype) - { - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: - if (frag_offset == fragq->size) - fragq->state = MSG_FRAG_STATE_END; - else - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Message %" PRIu64 " is NOT complete yet: %" PRIu64 " != %" PRIu64 "\n", - chn, - GNUNET_ntohll (mmsg->message_id), - frag_offset, - fragq->size); - break; - - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL: - /* Drop message without delivering to client if it's a single fragment */ - fragq->state = - (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == first_ptype) - ? MSG_FRAG_STATE_DROP - : MSG_FRAG_STATE_CANCEL; - } - - switch (fragq->state) - { - case MSG_FRAG_STATE_DATA: - case MSG_FRAG_STATE_END: - case MSG_FRAG_STATE_CANCEL: - if (GNUNET_NO == fragq->is_queued) - { - GNUNET_CONTAINER_heap_insert (chn->recv_msgs, NULL, - GNUNET_ntohll (mmsg->message_id)); - fragq->is_queued = GNUNET_YES; - } - } - - fragq->size += size; - GNUNET_CONTAINER_heap_insert (fragq->fragments, NULL, - GNUNET_ntohll (mmsg->fragment_id)); -} - - -/** - * Run fragment queue of a message. - * - * Send fragments of a message in order to client, after all modifiers arrived - * from multicast. - * - * @param chn - * Channel. - * @param msg_id - * ID of the message @a fragq belongs to. - * @param fragq - * Fragment queue of the message. - * @param drop - * Drop message without delivering to client? - * #GNUNET_YES or #GNUNET_NO. - */ -static void -fragment_queue_run (struct Channel *chn, uint64_t msg_id, - struct FragmentQueue *fragq, uint8_t drop) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Running message fragment queue for message %" PRIu64 " (state: %u).\n", - chn, - msg_id, - fragq->state); - - struct GNUNET_CONTAINER_MultiHashMap - *chan_msgs = GNUNET_CONTAINER_multihashmap_get (recv_cache, - &chn->pub_key_hash); - GNUNET_assert (NULL != chan_msgs); - uint64_t frag_id; - - while (GNUNET_YES == GNUNET_CONTAINER_heap_peek2 (fragq->fragments, NULL, - &frag_id)) - { - struct GNUNET_HashCode frag_id_hash; - hash_key_from_hll (&frag_id_hash, frag_id); - struct RecvCacheEntry *cache_entry - = GNUNET_CONTAINER_multihashmap_get (chan_msgs, &frag_id_hash); - if (cache_entry != NULL) - { - if (GNUNET_NO == drop) - { - client_send_mcast_msg (chn, cache_entry->mmsg, 0); - } - if (cache_entry->ref_count <= 1) - { - GNUNET_CONTAINER_multihashmap_remove (chan_msgs, &frag_id_hash, - cache_entry); - GNUNET_free (cache_entry->mmsg); - GNUNET_free (cache_entry); - } - else - { - cache_entry->ref_count--; - } - } -#if CACHE_AGING_IMPLEMENTED - else if (GNUNET_NO == drop) - { - /* TODO: fragment not in cache anymore, retrieve it from PSYCstore */ - } -#endif - - GNUNET_CONTAINER_heap_remove_root (fragq->fragments); - } - - if (MSG_FRAG_STATE_END <= fragq->state) - { - struct GNUNET_HashCode msg_id_hash; - hash_key_from_hll (&msg_id_hash, msg_id); - - GNUNET_CONTAINER_multihashmap_remove (chn->recv_frags, &msg_id_hash, fragq); - GNUNET_CONTAINER_heap_destroy (fragq->fragments); - GNUNET_free (fragq); - } - else - { - fragq->is_queued = GNUNET_NO; - } -} - - -struct StateModifyClosure -{ - struct Channel *channel; - uint64_t msg_id; - struct GNUNET_HashCode msg_id_hash; -}; - - -void -store_recv_state_modify_result (void *cls, int64_t result, - const char *err_msg, uint16_t err_msg_size) -{ - struct StateModifyClosure *mcls = cls; - struct Channel *chn = mcls->channel; - uint64_t msg_id = mcls->msg_id; - - struct FragmentQueue * - fragq = GNUNET_CONTAINER_multihashmap_get (chn->recv_frags, &mcls->msg_id_hash); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p GNUNET_PSYCSTORE_state_modify() returned %" PRId64 " (%.*s)\n", - chn, result, err_msg_size, err_msg); - - switch (result) - { - case GNUNET_OK: - case GNUNET_NO: - if (NULL != fragq) - fragq->state_is_modified = GNUNET_YES; - if (chn->max_state_message_id < msg_id) - chn->max_state_message_id = msg_id; - if (chn->max_message_id < msg_id) - chn->max_message_id = msg_id; - - if (NULL != fragq) - fragment_queue_run (chn, msg_id, fragq, MSG_FRAG_STATE_DROP == fragq->state); - GNUNET_CONTAINER_heap_remove_root (chn->recv_msgs); - message_queue_run (chn); - break; - - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%p GNUNET_PSYCSTORE_state_modify() failed with error %" PRId64 " (%.*s)\n", - chn, result, err_msg_size, err_msg); - /** @todo FIXME: handle state_modify error */ - } -} - - -/** - * Run message queue. - * - * Send messages in queue to client in order after a message has arrived from - * multicast, according to the following: - * - A message is only sent if all of its modifiers arrived. - * - A stateful message is only sent if the previous stateful message - * has already been delivered to the client. - * - * @param chn Channel. - * - * @return Number of messages removed from queue and sent to client. - */ -static uint64_t -message_queue_run (struct Channel *chn) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Running message queue.\n", chn); - uint64_t n = 0; - uint64_t msg_id; - - while (GNUNET_YES == GNUNET_CONTAINER_heap_peek2 (chn->recv_msgs, NULL, - &msg_id)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Processing message %" PRIu64 " in queue.\n", chn, msg_id); - struct GNUNET_HashCode msg_id_hash; - hash_key_from_hll (&msg_id_hash, msg_id); - - struct FragmentQueue * - fragq = GNUNET_CONTAINER_multihashmap_get (chn->recv_frags, &msg_id_hash); - - if (NULL == fragq || fragq->state <= MSG_FRAG_STATE_HEADER) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p No fragq (%p) or header not complete.\n", - chn, fragq); - break; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Fragment queue entry: state: %u, state delta: " - "%" PRIu64 " - %" PRIu64 " ?= %" PRIu64 "\n", - chn, fragq->state, msg_id, fragq->state_delta, chn->max_state_message_id); - - if (MSG_FRAG_STATE_DATA <= fragq->state) - { - /* Check if there's a missing message before the current one */ - if (GNUNET_PSYC_STATE_NOT_MODIFIED == fragq->state_delta) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%p state NOT modified\n", chn); - - if (!(fragq->flags & GNUNET_PSYC_MESSAGE_ORDER_ANY) - && (chn->max_message_id != msg_id - 1 - && chn->max_message_id != msg_id)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Out of order message. " - "(%" PRIu64 " != %" PRIu64 " - 1)\n", - chn, chn->max_message_id, msg_id); - break; - // FIXME: keep track of messages processed in this queue run, - // and only stop after reaching the end - } - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%p state modified\n", chn); - if (GNUNET_YES != fragq->state_is_modified) - { - if (msg_id - fragq->state_delta != chn->max_state_message_id) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Out of order stateful message. " - "(%" PRIu64 " - %" PRIu64 " != %" PRIu64 ")\n", - chn, msg_id, fragq->state_delta, chn->max_state_message_id); - break; - // FIXME: keep track of messages processed in this queue run, - // and only stop after reaching the end - } - - struct StateModifyClosure *mcls = GNUNET_malloc (sizeof (*mcls)); - mcls->channel = chn; - mcls->msg_id = msg_id; - mcls->msg_id_hash = msg_id_hash; - - /* Apply modifiers to state in PSYCstore */ - GNUNET_PSYCSTORE_state_modify (store, &chn->pub_key, msg_id, - fragq->state_delta, - store_recv_state_modify_result, mcls); - break; // continue after asynchronous state modify result - } - } - chn->max_message_id = msg_id; - } - fragment_queue_run (chn, msg_id, fragq, MSG_FRAG_STATE_DROP == fragq->state); - GNUNET_CONTAINER_heap_remove_root (chn->recv_msgs); - n++; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Removed %" PRIu64 " messages from queue.\n", chn, n); - return n; -} - - -/** - * Drop message queue of a channel. - * - * Remove all messages in queue without sending it to clients. - * - * @param chn Channel. - * - * @return Number of messages removed from queue. - */ -static uint64_t -message_queue_drop (struct Channel *chn) -{ - uint64_t n = 0; - uint64_t msg_id; - while (GNUNET_YES == GNUNET_CONTAINER_heap_peek2 (chn->recv_msgs, NULL, - &msg_id)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "%p Dropping message %" PRIu64 " from queue.\n", chn, msg_id); - struct GNUNET_HashCode msg_id_hash; - hash_key_from_hll (&msg_id_hash, msg_id); - - struct FragmentQueue * - fragq = GNUNET_CONTAINER_multihashmap_get (chn->recv_frags, &msg_id_hash); - GNUNET_assert (NULL != fragq); - fragment_queue_run (chn, msg_id, fragq, GNUNET_YES); - GNUNET_CONTAINER_heap_remove_root (chn->recv_msgs); - n++; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Removed %" PRIu64 " messages from queue.\n", chn, n); - return n; -} - - -/** - * Received result of GNUNET_PSYCSTORE_fragment_store(). - */ -static void -store_recv_fragment_store_result (void *cls, int64_t result, - const char *err_msg, uint16_t err_msg_size) -{ - struct Channel *chn = cls; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p GNUNET_PSYCSTORE_fragment_store() returned %" PRId64 " (%.*s)\n", - chn, result, err_msg_size, err_msg); -} - - -/** - * Handle incoming message fragment from multicast. - * - * Store it using PSYCstore and send it to the clients of the channel in order. - */ -static void -mcast_recv_message (void *cls, const struct GNUNET_MULTICAST_MessageHeader *mmsg) -{ - struct Channel *chn = cls; - uint16_t size = ntohs (mmsg->header.size); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Received multicast message of size %u. " - "fragment_id=%" PRIu64 ", message_id=%" PRIu64 - ", fragment_offset=%" PRIu64 ", flags=%" PRIu64 "\n", - chn, size, - GNUNET_ntohll (mmsg->fragment_id), - GNUNET_ntohll (mmsg->message_id), - GNUNET_ntohll (mmsg->fragment_offset), - GNUNET_ntohll (mmsg->flags)); - - GNUNET_PSYCSTORE_fragment_store (store, &chn->pub_key, mmsg, 0, - &store_recv_fragment_store_result, chn); - - uint16_t first_ptype = 0, last_ptype = 0; - int check = GNUNET_PSYC_receive_check_parts (size - sizeof (*mmsg), - (const char *) &mmsg[1], - &first_ptype, &last_ptype); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Message check result %d, first part type %u, last part type %u\n", - chn, check, first_ptype, last_ptype); - if (GNUNET_SYSERR == check) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "%p Dropping incoming multicast message with invalid parts.\n", - chn); - GNUNET_break_op (0); - return; - } - - fragment_queue_insert (chn, mmsg, first_ptype, last_ptype); - message_queue_run (chn); -} - - -/** - * Incoming request fragment from multicast for a master. - * - * @param cls Master. - * @param req The request. - */ -static void -mcast_recv_request (void *cls, - const struct GNUNET_MULTICAST_RequestHeader *req) -{ - struct Master *mst = cls; - uint16_t size = ntohs (req->header.size); - - char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&req->member_pub_key); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Received multicast request of size %u from %s.\n", - mst, size, str); - GNUNET_free (str); - - uint16_t first_ptype = 0, last_ptype = 0; - if (GNUNET_SYSERR - == GNUNET_PSYC_receive_check_parts (size - sizeof (*req), - (const char *) &req[1], - &first_ptype, &last_ptype)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "%p Dropping incoming multicast request with invalid parts.\n", - mst); - GNUNET_break_op (0); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Message parts: first: type %u, last: type %u\n", - first_ptype, last_ptype); - - /* FIXME: in-order delivery */ - client_send_mcast_req (mst, req); -} - - -/** - * Response from PSYCstore with the current counter values for a channel master. - */ -static void -store_recv_master_counters (void *cls, int result, uint64_t max_fragment_id, - uint64_t max_message_id, uint64_t max_group_generation, - uint64_t max_state_message_id) -{ - struct Master *mst = cls; - struct Channel *chn = &mst->channel; - chn->store_op = NULL; - - struct GNUNET_PSYC_CountersResultMessage res; - res.header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MASTER_START_ACK); - res.header.size = htons (sizeof (res)); - res.result_code = htonl (result); - res.max_message_id = GNUNET_htonll (max_message_id); - - if (GNUNET_OK == result || GNUNET_NO == result) - { - mst->max_message_id = max_message_id; - chn->max_message_id = max_message_id; - chn->max_state_message_id = max_state_message_id; - mst->max_group_generation = max_group_generation; - mst->origin - = GNUNET_MULTICAST_origin_start (cfg, &mst->priv_key, max_fragment_id, - mcast_recv_join_request, - mcast_recv_replay_fragment, - mcast_recv_replay_message, - mcast_recv_request, - mcast_recv_message, chn); - chn->is_ready = GNUNET_YES; - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%p GNUNET_PSYCSTORE_counters_get() " - "returned %d for channel %s.\n", - chn, result, GNUNET_h2s (&chn->pub_key_hash)); - } - - client_send_msg (chn, &res.header); -} - - -/** - * Response from PSYCstore with the current counter values for a channel slave. - */ -void -store_recv_slave_counters (void *cls, int result, uint64_t max_fragment_id, - uint64_t max_message_id, uint64_t max_group_generation, - uint64_t max_state_message_id) -{ - struct Slave *slv = cls; - struct Channel *chn = &slv->channel; - chn->store_op = NULL; - - struct GNUNET_PSYC_CountersResultMessage res; - res.header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN_ACK); - res.header.size = htons (sizeof (res)); - res.result_code = htonl (result); - res.max_message_id = GNUNET_htonll (max_message_id); - - if (GNUNET_YES == result || GNUNET_NO == result) - { - chn->max_message_id = max_message_id; - chn->max_state_message_id = max_state_message_id; - slv->member - = GNUNET_MULTICAST_member_join (cfg, &chn->pub_key, &slv->priv_key, - &slv->origin, - slv->relay_count, slv->relays, - &slv->join_msg->header, - mcast_recv_join_request, - mcast_recv_join_decision, - mcast_recv_replay_fragment, - mcast_recv_replay_message, - mcast_recv_message, chn); - if (NULL != slv->join_msg) - { - GNUNET_free (slv->join_msg); - slv->join_msg = NULL; - } - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%p GNUNET_PSYCSTORE_counters_get() " - "returned %d for channel %s.\n", - chn, result, GNUNET_h2s (&chn->pub_key_hash)); - } - - client_send_msg (chn, &res.header); -} - - -static void -channel_init (struct Channel *chn) -{ - chn->recv_msgs - = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); - chn->recv_frags = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); -} - - -/** - * Handle a connecting client starting a channel master. - */ -static void -handle_client_master_start (void *cls, - const struct MasterStartRequest *req) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - - struct GNUNET_CRYPTO_EddsaPublicKey pub_key; - struct GNUNET_HashCode pub_key_hash; - - GNUNET_CRYPTO_eddsa_key_get_public (&req->channel_key, &pub_key); - GNUNET_CRYPTO_hash (&pub_key, sizeof (pub_key), &pub_key_hash); - - struct Master * - mst = GNUNET_CONTAINER_multihashmap_get (masters, &pub_key_hash); - struct Channel *chn; - - if (NULL == mst) - { - mst = GNUNET_malloc (sizeof (*mst)); - mst->policy = ntohl (req->policy); - mst->priv_key = req->channel_key; - mst->join_reqs = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - - chn = c->channel = &mst->channel; - chn->master = mst; - chn->is_master = GNUNET_YES; - chn->pub_key = pub_key; - chn->pub_key_hash = pub_key_hash; - channel_init (chn); - - GNUNET_CONTAINER_multihashmap_put (masters, &chn->pub_key_hash, chn, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - chn->store_op = GNUNET_PSYCSTORE_counters_get (store, &chn->pub_key, - store_recv_master_counters, mst); - } - else - { - chn = &mst->channel; - - struct GNUNET_PSYC_CountersResultMessage *res; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg (res, GNUNET_MESSAGE_TYPE_PSYC_MASTER_START_ACK); - res->result_code = htonl (GNUNET_OK); - res->max_message_id = GNUNET_htonll (mst->max_message_id); - - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env); - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Client connected as master to channel %s.\n", - mst, GNUNET_h2s (&chn->pub_key_hash)); - - struct ClientList *cli = GNUNET_malloc (sizeof (*cli)); - cli->client = client; - GNUNET_CONTAINER_DLL_insert (chn->clients_head, chn->clients_tail, cli); - - GNUNET_SERVICE_client_continue (client); -} - - -static int -check_client_slave_join (void *cls, - const struct SlaveJoinRequest *req) -{ - return GNUNET_OK; -} - - -/** - * Handle a connecting client joining as a channel slave. - */ -static void -handle_client_slave_join (void *cls, - const struct SlaveJoinRequest *req) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - - uint16_t req_size = ntohs (req->header.size); - - struct GNUNET_CRYPTO_EcdsaPublicKey slv_pub_key; - struct GNUNET_HashCode pub_key_hash, slv_pub_hash; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "got join request from client %p\n", - client); - GNUNET_CRYPTO_ecdsa_key_get_public (&req->slave_key, &slv_pub_key); - GNUNET_CRYPTO_hash (&slv_pub_key, sizeof (slv_pub_key), &slv_pub_hash); - GNUNET_CRYPTO_hash (&req->channel_pub_key, sizeof (req->channel_pub_key), &pub_key_hash); - - struct GNUNET_CONTAINER_MultiHashMap * - chn_slv = GNUNET_CONTAINER_multihashmap_get (channel_slaves, &pub_key_hash); - struct Slave *slv = NULL; - struct Channel *chn; - - if (NULL != chn_slv) - { - slv = GNUNET_CONTAINER_multihashmap_get (chn_slv, &slv_pub_hash); - } - if (NULL == slv) - { - slv = GNUNET_malloc (sizeof (*slv)); - slv->priv_key = req->slave_key; - slv->pub_key = slv_pub_key; - slv->pub_key_hash = slv_pub_hash; - slv->origin = req->origin; - slv->relay_count = ntohl (req->relay_count); - slv->join_flags = ntohl (req->flags); - - const struct GNUNET_PeerIdentity * - relays = (const struct GNUNET_PeerIdentity *) &req[1]; - uint16_t relay_size = slv->relay_count * sizeof (*relays); - uint16_t join_msg_size = 0; - - if (sizeof (*req) + relay_size + sizeof (struct GNUNET_MessageHeader) - <= req_size) - { - struct GNUNET_PSYC_Message * - join_msg = (struct GNUNET_PSYC_Message *) (((char *) &req[1]) + relay_size); - join_msg_size = ntohs (join_msg->header.size); - slv->join_msg = GNUNET_malloc (join_msg_size); - GNUNET_memcpy (slv->join_msg, join_msg, join_msg_size); - } - if (sizeof (*req) + relay_size + join_msg_size != req_size) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%u + %u + %u != %u\n", - (unsigned int) sizeof (*req), - relay_size, - join_msg_size, - req_size); - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - GNUNET_free (slv); - return; - } - if (0 < slv->relay_count) - { - slv->relays = GNUNET_malloc (relay_size); - GNUNET_memcpy (slv->relays, &req[1], relay_size); - } - - chn = c->channel = &slv->channel; - chn->slave = slv; - chn->is_master = GNUNET_NO; - chn->pub_key = req->channel_pub_key; - chn->pub_key_hash = pub_key_hash; - channel_init (chn); - - if (NULL == chn_slv) - { - chn_slv = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); - GNUNET_CONTAINER_multihashmap_put (channel_slaves, &chn->pub_key_hash, chn_slv, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - } - GNUNET_CONTAINER_multihashmap_put (chn_slv, &slv->pub_key_hash, chn, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - GNUNET_CONTAINER_multihashmap_put (slaves, &chn->pub_key_hash, chn, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - chn->store_op = GNUNET_PSYCSTORE_counters_get (store, &chn->pub_key, - &store_recv_slave_counters, slv); - } - else - { - chn = &slv->channel; - - struct GNUNET_PSYC_CountersResultMessage *res; - - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg (res, GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN_ACK); - res->result_code = htonl (GNUNET_OK); - res->max_message_id = GNUNET_htonll (chn->max_message_id); - - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env); - - if (GNUNET_PSYC_SLAVE_JOIN_LOCAL & slv->join_flags) - { - mcast_recv_join_decision (slv, GNUNET_YES, - NULL, 0, NULL, NULL); - } - else if (NULL == slv->member) - { - slv->member - = GNUNET_MULTICAST_member_join (cfg, &chn->pub_key, &slv->priv_key, - &slv->origin, - slv->relay_count, slv->relays, - &slv->join_msg->header, - &mcast_recv_join_request, - &mcast_recv_join_decision, - &mcast_recv_replay_fragment, - &mcast_recv_replay_message, - &mcast_recv_message, chn); - if (NULL != slv->join_msg) - { - GNUNET_free (slv->join_msg); - slv->join_msg = NULL; - } - } - else if (NULL != slv->join_dcsn) - { - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_copy (&slv->join_dcsn->header); - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env); - } - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Client %p connected as slave to channel %s.\n", - client, - GNUNET_h2s (&chn->pub_key_hash)); - - struct ClientList *cli = GNUNET_malloc (sizeof (*cli)); - cli->client = client; - GNUNET_CONTAINER_DLL_insert (chn->clients_head, chn->clients_tail, cli); - - GNUNET_SERVICE_client_continue (client); -} - - -struct JoinDecisionClosure -{ - int32_t is_admitted; - struct GNUNET_MessageHeader *msg; -}; - - -/** - * Iterator callback for sending join decisions to multicast. - */ -static int -mcast_send_join_decision (void *cls, const struct GNUNET_HashCode *pub_key_hash, - void *value) -{ - struct JoinDecisionClosure *jcls = cls; - struct GNUNET_MULTICAST_JoinHandle *jh = value; - // FIXME: add relays - GNUNET_MULTICAST_join_decision (jh, jcls->is_admitted, 0, NULL, jcls->msg); - return GNUNET_YES; -} - - -static int -check_client_join_decision (void *cls, - const struct GNUNET_PSYC_JoinDecisionMessage *dcsn) -{ - return GNUNET_OK; -} - - -/** - * Join decision from client. - */ -static void -handle_client_join_decision (void *cls, - const struct GNUNET_PSYC_JoinDecisionMessage *dcsn) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - struct Channel *chn = c->channel; - if (NULL == chn) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - GNUNET_assert (GNUNET_YES == chn->is_master); - struct Master *mst = chn->master; - - struct JoinDecisionClosure jcls; - jcls.is_admitted = ntohl (dcsn->is_admitted); - jcls.msg - = (sizeof (*dcsn) + sizeof (*jcls.msg) <= ntohs (dcsn->header.size)) - ? (struct GNUNET_MessageHeader *) &dcsn[1] - : NULL; - - struct GNUNET_HashCode slave_pub_hash; - GNUNET_CRYPTO_hash (&dcsn->slave_pub_key, sizeof (dcsn->slave_pub_key), - &slave_pub_hash); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Got join decision (%d) from client for channel %s..\n", - mst, jcls.is_admitted, GNUNET_h2s (&chn->pub_key_hash)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p ..and slave %s.\n", - mst, GNUNET_h2s (&slave_pub_hash)); - - GNUNET_CONTAINER_multihashmap_get_multiple (mst->join_reqs, &slave_pub_hash, - &mcast_send_join_decision, &jcls); - GNUNET_CONTAINER_multihashmap_remove_all (mst->join_reqs, &slave_pub_hash); - GNUNET_SERVICE_client_continue (client); -} - - -static void -channel_part_cb (void *cls) -{ - struct GNUNET_SERVICE_Client *client = cls; - struct GNUNET_MQ_Envelope *env; - - env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_PSYC_PART_ACK); - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), - env); -} - - -static void -handle_client_part_request (void *cls, - const struct GNUNET_MessageHeader *msg) -{ - struct Client *c = cls; - - c->channel->is_disconnecting = GNUNET_YES; - if (GNUNET_YES == c->channel->is_master) - { - struct Master *mst = (struct Master *) c->channel; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Got part request from master %p\n", - mst); - GNUNET_assert (NULL != mst->origin); - GNUNET_MULTICAST_origin_stop (mst->origin, channel_part_cb, c->client); - } - else - { - struct Slave *slv = (struct Slave *) c->channel; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Got part request from slave %p\n", - slv); - GNUNET_assert (NULL != slv->member); - GNUNET_MULTICAST_member_part (slv->member, channel_part_cb, c->client); - } - GNUNET_SERVICE_client_continue (c->client); -} - - -/** - * Send acknowledgement to a client. - * - * Sent after a message fragment has been passed on to multicast. - * - * @param chn The channel struct for the client. - */ -static void -send_message_ack (struct Channel *chn, struct GNUNET_SERVICE_Client *client) -{ - struct GNUNET_MessageHeader *res; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg (res, GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK); - - /* FIXME? */ - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env); -} - - -/** - * Callback for the transmit functions of multicast. - */ -static int -transmit_notify (void *cls, size_t *data_size, void *data) -{ - struct Channel *chn = cls; - struct TransmitMessage *tmit_msg = chn->tmit_head; - - if (NULL == tmit_msg || *data_size < tmit_msg->size) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p transmit_notify: nothing to send.\n", chn); - if (NULL != tmit_msg && *data_size < tmit_msg->size) - GNUNET_break (0); - *data_size = 0; - return GNUNET_NO; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p transmit_notify: sending %u bytes.\n", chn, tmit_msg->size); - - *data_size = tmit_msg->size; - GNUNET_memcpy (data, &tmit_msg[1], *data_size); - - int ret - = (tmit_msg->last_ptype < GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END) - ? GNUNET_NO - : GNUNET_YES; - - /* FIXME: handle disconnecting clients */ - if (NULL != tmit_msg->client) - send_message_ack (chn, tmit_msg->client); - - GNUNET_CONTAINER_DLL_remove (chn->tmit_head, chn->tmit_tail, tmit_msg); - - if (NULL != chn->tmit_head) - { - GNUNET_SCHEDULER_add_now (&schedule_transmit_message, chn); - } - else if (GNUNET_YES == chn->is_disconnecting - && tmit_msg->last_ptype < GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END) - { - /* FIXME: handle partial message (when still in_transmit) */ - GNUNET_free (tmit_msg); - return GNUNET_SYSERR; - } - GNUNET_free (tmit_msg); - return ret; -} - - -/** - * Callback for the transmit functions of multicast. - */ -static int -master_transmit_notify (void *cls, size_t *data_size, void *data) -{ - int ret = transmit_notify (cls, data_size, data); - - if (GNUNET_YES == ret) - { - struct Master *mst = cls; - mst->tmit_handle = NULL; - } - return ret; -} - - -/** - * Callback for the transmit functions of multicast. - */ -static int -slave_transmit_notify (void *cls, size_t *data_size, void *data) -{ - int ret = transmit_notify (cls, data_size, data); - - if (GNUNET_YES == ret) - { - struct Slave *slv = cls; - slv->tmit_handle = NULL; - } - return ret; -} - - -/** - * Transmit a message from a channel master to the multicast group. - */ -static void -master_transmit_message (struct Master *mst) -{ - struct Channel *chn = &mst->channel; - struct TransmitMessage *tmit_msg = chn->tmit_head; - if (NULL == tmit_msg) - return; - if (NULL == mst->tmit_handle) - { - mst->tmit_handle = GNUNET_MULTICAST_origin_to_all (mst->origin, - tmit_msg->id, - mst->max_group_generation, - &master_transmit_notify, - mst); - } - else - { - GNUNET_MULTICAST_origin_to_all_resume (mst->tmit_handle); - } -} - - -/** - * Transmit a message from a channel slave to the multicast group. - */ -static void -slave_transmit_message (struct Slave *slv) -{ - if (NULL == slv->channel.tmit_head) - return; - if (NULL == slv->tmit_handle) - { - slv->tmit_handle = GNUNET_MULTICAST_member_to_origin (slv->member, - slv->channel.tmit_head->id, - &slave_transmit_notify, - slv); - } - else - { - GNUNET_MULTICAST_member_to_origin_resume (slv->tmit_handle); - } -} - - -static void -transmit_message (struct Channel *chn) -{ - chn->is_master - ? master_transmit_message (chn->master) - : slave_transmit_message (chn->slave); -} - - -/** - * Queue a message from a channel master for sending to the multicast group. - */ -static void -master_queue_message (struct Master *mst, struct TransmitMessage *tmit_msg) -{ - if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == tmit_msg->first_ptype) - { - tmit_msg->id = ++mst->max_message_id; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p master_queue_message: message_id=%" PRIu64 "\n", - mst, tmit_msg->id); - struct GNUNET_PSYC_MessageMethod *pmeth - = (struct GNUNET_PSYC_MessageMethod *) &tmit_msg[1]; - - if (pmeth->flags & GNUNET_PSYC_MASTER_TRANSMIT_STATE_RESET) - { - pmeth->state_delta = GNUNET_htonll (GNUNET_PSYC_STATE_RESET); - } - else if (pmeth->flags & GNUNET_PSYC_MASTER_TRANSMIT_STATE_MODIFY) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p master_queue_message: state_delta=%" PRIu64 "\n", - mst, tmit_msg->id - mst->max_state_message_id); - pmeth->state_delta = GNUNET_htonll (tmit_msg->id - - mst->max_state_message_id); - mst->max_state_message_id = tmit_msg->id; - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p master_queue_message: state not modified\n", mst); - pmeth->state_delta = GNUNET_htonll (GNUNET_PSYC_STATE_NOT_MODIFIED); - } - - if (pmeth->flags & GNUNET_PSYC_MASTER_TRANSMIT_STATE_HASH) - { - /// @todo add state_hash to PSYC header - } - } -} - - -/** - * Queue a message from a channel slave for sending to the multicast group. - */ -static void -slave_queue_message (struct Slave *slv, struct TransmitMessage *tmit_msg) -{ - if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == tmit_msg->first_ptype) - { - struct GNUNET_PSYC_MessageMethod *pmeth - = (struct GNUNET_PSYC_MessageMethod *) &tmit_msg[1]; - pmeth->state_delta = GNUNET_htonll (GNUNET_PSYC_STATE_NOT_MODIFIED); - tmit_msg->id = ++slv->max_request_id; - } -} - - -/** - * Queue PSYC message parts for sending to multicast. - * - * @param chn - * Channel to send to. - * @param client - * Client the message originates from. - * @param data_size - * Size of @a data. - * @param data - * Concatenated message parts. - * @param first_ptype - * First message part type in @a data. - * @param last_ptype - * Last message part type in @a data. - */ -static struct TransmitMessage * -queue_message (struct Channel *chn, - struct GNUNET_SERVICE_Client *client, - size_t data_size, - const void *data, - uint16_t first_ptype, uint16_t last_ptype) -{ - struct TransmitMessage * - tmit_msg = GNUNET_malloc (sizeof (*tmit_msg) + data_size); - GNUNET_memcpy (&tmit_msg[1], data, data_size); - tmit_msg->client = client; - tmit_msg->size = data_size; - tmit_msg->first_ptype = first_ptype; - tmit_msg->last_ptype = last_ptype; - - /* FIXME: separate queue per message ID */ - - GNUNET_CONTAINER_DLL_insert_tail (chn->tmit_head, chn->tmit_tail, tmit_msg); - - chn->is_master - ? master_queue_message (chn->master, tmit_msg) - : slave_queue_message (chn->slave, tmit_msg); - return tmit_msg; -} - - -/** - * Cancel transmission of current message. - * - * @param chn Channel to send to. - * @param client Client the message originates from. - */ -static void -transmit_cancel (struct Channel *chn, struct GNUNET_SERVICE_Client *client) -{ - uint16_t type = GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL; - - struct GNUNET_MessageHeader msg; - msg.size = htons (sizeof (msg)); - msg.type = htons (type); - - queue_message (chn, client, sizeof (msg), &msg, type, type); - transmit_message (chn); - - /* FIXME: cleanup */ -} - - -static int -check_client_psyc_message (void *cls, - const struct GNUNET_MessageHeader *msg) -{ - return GNUNET_OK; -} - - -/** - * Incoming message from a master or slave client. - */ -static void -handle_client_psyc_message (void *cls, - const struct GNUNET_MessageHeader *msg) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - struct Channel *chn = c->channel; - if (NULL == chn) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Received message from client.\n", chn); - GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, msg); - - if (GNUNET_YES != chn->is_ready) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "%p Channel is not ready yet, disconnecting client %p.\n", - chn, - client); - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - - uint16_t size = ntohs (msg->size); - if (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < size - sizeof (*msg)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%p Message payload too large: %u < %u.\n", - chn, - (unsigned int) GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD, - (unsigned int) (size - sizeof (*msg))); - GNUNET_break (0); - transmit_cancel (chn, client); - GNUNET_SERVICE_client_drop (client); - return; - } - - uint16_t first_ptype = 0, last_ptype = 0; - if (GNUNET_SYSERR - == GNUNET_PSYC_receive_check_parts (size - sizeof (*msg), - (const char *) &msg[1], - &first_ptype, &last_ptype)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%p Received invalid message part from client.\n", chn); - GNUNET_break (0); - transmit_cancel (chn, client); - GNUNET_SERVICE_client_drop (client); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Received message with first part type %u and last part type %u.\n", - chn, first_ptype, last_ptype); - - queue_message (chn, client, size - sizeof (*msg), &msg[1], - first_ptype, last_ptype); - transmit_message (chn); - /* FIXME: send a few ACKs even before transmit_notify is called */ - - GNUNET_SERVICE_client_continue (client); -}; - - -/** - * Received result of GNUNET_PSYCSTORE_membership_store() - */ -static void -store_recv_membership_store_result (void *cls, - int64_t result, - const char *err_msg, - uint16_t err_msg_size) -{ - struct Operation *op = cls; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p GNUNET_PSYCSTORE_membership_store() returned %" PRId64 " (%.*s)\n", - op->channel, - result, - (int) err_msg_size, - err_msg); - - if (NULL != op->client) - client_send_result (op->client, op->op_id, result, err_msg, err_msg_size); - op_remove (op); -} - - -/** - * Client requests to add/remove a slave in the membership database. - */ -static void -handle_client_membership_store (void *cls, - const struct ChannelMembershipStoreRequest *req) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - struct Channel *chn = c->channel; - if (NULL == chn) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - - struct Operation *op = op_add (chn, client, req->op_id, 0); - - uint64_t announced_at = GNUNET_ntohll (req->announced_at); - uint64_t effective_since = GNUNET_ntohll (req->effective_since); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Received membership store request from client.\n", chn); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p did_join: %u, announced_at: %" PRIu64 ", effective_since: %" PRIu64 "\n", - chn, req->did_join, announced_at, effective_since); - - GNUNET_PSYCSTORE_membership_store (store, &chn->pub_key, &req->slave_pub_key, - req->did_join, announced_at, effective_since, - 0, /* FIXME: group_generation */ - &store_recv_membership_store_result, op); - GNUNET_SERVICE_client_continue (client); -} - - -/** - * Received a fragment for GNUNET_PSYCSTORE_fragment_get(), - * in response to a history request from a client. - */ -static int -store_recv_fragment_history (void *cls, - struct GNUNET_MULTICAST_MessageHeader *mmsg, - enum GNUNET_PSYCSTORE_MessageFlags flags) -{ - struct Operation *op = cls; - if (NULL == op->client) - { /* Requesting client already disconnected. */ - return GNUNET_NO; - } - struct Channel *chn = op->channel; - - struct GNUNET_PSYC_MessageHeader *pmsg; - uint16_t msize = ntohs (mmsg->header.size); - uint16_t psize = sizeof (*pmsg) + msize - sizeof (*mmsg); - - struct GNUNET_OperationResultMessage * - res = GNUNET_malloc (sizeof (*res) + psize); - res->header.size = htons (sizeof (*res) + psize); - res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT); - res->op_id = op->op_id; - res->result_code = GNUNET_htonll (GNUNET_OK); - - pmsg = (struct GNUNET_PSYC_MessageHeader *) &res[1]; - GNUNET_PSYC_message_header_init (pmsg, mmsg, flags | GNUNET_PSYC_MESSAGE_HISTORIC); - GNUNET_memcpy (&res[1], pmsg, psize); - - /** @todo FIXME: send only to requesting client */ - client_send_msg (chn, &res->header); - - GNUNET_free (res); - return GNUNET_YES; -} - - -/** - * Received the result of GNUNET_PSYCSTORE_fragment_get(), - * in response to a history request from a client. - */ -static void -store_recv_fragment_history_result (void *cls, int64_t result, - const char *err_msg, uint16_t err_msg_size) -{ - struct Operation *op = cls; - if (NULL == op->client) - { /* Requesting client already disconnected. */ - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p History replay #%" PRIu64 ": " - "PSYCSTORE returned %" PRId64 " (%.*s)\n", - op->channel, GNUNET_ntohll (op->op_id), result, err_msg_size, err_msg); - - if (op->flags & GNUNET_PSYC_HISTORY_REPLAY_REMOTE) - { - /** @todo Multicast replay request for messages not found locally. */ - } - - client_send_result (op->client, op->op_id, result, err_msg, err_msg_size); - op_remove (op); -} - - -static int -check_client_history_replay (void *cls, - const struct GNUNET_PSYC_HistoryRequestMessage *req) -{ - return GNUNET_OK; -} - - -/** - * Client requests channel history. - */ -static void -handle_client_history_replay (void *cls, - const struct GNUNET_PSYC_HistoryRequestMessage *req) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - struct Channel *chn = c->channel; - if (NULL == chn) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - - uint16_t size = ntohs (req->header.size); - const char *method_prefix = (const char *) &req[1]; - - if (size < sizeof (*req) + 1 - || '\0' != method_prefix[size - sizeof (*req) - 1]) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%p History replay #%" PRIu64 ": " - "invalid method prefix. size: %u < %u?\n", - chn, - GNUNET_ntohll (req->op_id), - size, - (unsigned int) sizeof (*req) + 1); - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - - struct Operation *op = op_add (chn, client, req->op_id, ntohl (req->flags)); - - if (0 == req->message_limit) - { - GNUNET_PSYCSTORE_message_get (store, &chn->pub_key, NULL, - GNUNET_ntohll (req->start_message_id), - GNUNET_ntohll (req->end_message_id), - 0, method_prefix, - &store_recv_fragment_history, - &store_recv_fragment_history_result, op); - } - else - { - GNUNET_PSYCSTORE_message_get_latest (store, &chn->pub_key, NULL, - GNUNET_ntohll (req->message_limit), - method_prefix, - &store_recv_fragment_history, - &store_recv_fragment_history_result, - op); - } - GNUNET_SERVICE_client_continue (client); -} - - -/** - * Received state var from PSYCstore, send it to client. - */ -static int -store_recv_state_var (void *cls, const char *name, - const void *value, uint32_t value_size) -{ - struct Operation *op = cls; - struct GNUNET_OperationResultMessage *res; - struct GNUNET_MQ_Envelope *env; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p state_get #%" PRIu64 " - received var from PSYCstore: %s\n", - op->channel, GNUNET_ntohll (op->op_id), name); - - if (NULL != name) /* First part */ - { - uint16_t name_size = strnlen (name, GNUNET_PSYC_MODIFIER_MAX_PAYLOAD) + 1; - struct GNUNET_PSYC_MessageModifier *mod; - env = GNUNET_MQ_msg_extra (res, - sizeof (*mod) + name_size + value_size, - GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT); - res->op_id = op->op_id; - - mod = (struct GNUNET_PSYC_MessageModifier *) &res[1]; - mod->header.size = htons (sizeof (*mod) + name_size + value_size); - mod->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER); - mod->name_size = htons (name_size); - mod->value_size = htonl (value_size); - mod->oper = htons (GNUNET_PSYC_OP_ASSIGN); - GNUNET_memcpy (&mod[1], name, name_size); - GNUNET_memcpy (((char *) &mod[1]) + name_size, value, value_size); - } - else /* Continuation */ - { - struct GNUNET_MessageHeader *mod; - env = GNUNET_MQ_msg_extra (res, - sizeof (*mod) + value_size, - GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT); - res->op_id = op->op_id; - - mod = (struct GNUNET_MessageHeader *) &res[1]; - mod->size = htons (sizeof (*mod) + value_size); - mod->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT); - GNUNET_memcpy (&mod[1], value, value_size); - } - - // FIXME: client might have been disconnected - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (op->client), env); - return GNUNET_YES; -} - - -/** - * Received result of GNUNET_PSYCSTORE_state_get() - * or GNUNET_PSYCSTORE_state_get_prefix() - */ -static void -store_recv_state_result (void *cls, int64_t result, - const char *err_msg, uint16_t err_msg_size) -{ - struct Operation *op = cls; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p state_get #%" PRIu64 ": " - "PSYCSTORE returned %" PRId64 " (%.*s)\n", - op->channel, GNUNET_ntohll (op->op_id), result, err_msg_size, err_msg); - - // FIXME: client might have been disconnected - client_send_result (op->client, op->op_id, result, err_msg, err_msg_size); - op_remove (op); -} - - -static int -check_client_state_get (void *cls, - const struct StateRequest *req) -{ - struct Client *c = cls; - struct Channel *chn = c->channel; - if (NULL == chn) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - - uint16_t name_size = ntohs (req->header.size) - sizeof (*req); - const char *name = (const char *) &req[1]; - if (0 == name_size || '\0' != name[name_size - 1]) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - - return GNUNET_OK; -} - - -/** - * Client requests best matching state variable from PSYCstore. - */ -static void -handle_client_state_get (void *cls, - const struct StateRequest *req) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - struct Channel *chn = c->channel; - - const char *name = (const char *) &req[1]; - struct Operation *op = op_add (chn, client, req->op_id, 0); - GNUNET_PSYCSTORE_state_get (store, &chn->pub_key, name, - &store_recv_state_var, - &store_recv_state_result, op); - GNUNET_SERVICE_client_continue (client); -} - - -static int -check_client_state_get_prefix (void *cls, - const struct StateRequest *req) -{ - struct Client *c = cls; - struct Channel *chn = c->channel; - if (NULL == chn) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - - uint16_t name_size = ntohs (req->header.size) - sizeof (*req); - const char *name = (const char *) &req[1]; - if (0 == name_size || '\0' != name[name_size - 1]) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - - return GNUNET_OK; -} - - -/** - * Client requests state variables with a given prefix from PSYCstore. - */ -static void -handle_client_state_get_prefix (void *cls, - const struct StateRequest *req) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - struct Channel *chn = c->channel; - - const char *name = (const char *) &req[1]; - struct Operation *op = op_add (chn, client, req->op_id, 0); - GNUNET_PSYCSTORE_state_get_prefix (store, &chn->pub_key, name, - &store_recv_state_var, - &store_recv_state_result, op); - GNUNET_SERVICE_client_continue (client); -} - - -/** - * Initialize the PSYC service. - * - * @param cls Closure. - * @param server The initialized server. - * @param c Configuration to use. - */ -static void -run (void *cls, - const struct GNUNET_CONFIGURATION_Handle *c, - struct GNUNET_SERVICE_Handle *svc) -{ - cfg = c; - service = svc; - store = GNUNET_PSYCSTORE_connect (cfg); - stats = GNUNET_STATISTICS_create ("psyc", cfg); - masters = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); - slaves = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); - channel_slaves = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - recv_cache = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); -} - - -/** - * Define "main" method using service macro. - */ -GNUNET_SERVICE_MAIN -("psyc", - GNUNET_SERVICE_OPTION_NONE, - &run, - &client_notify_connect, - &client_notify_disconnect, - NULL, - GNUNET_MQ_hd_fixed_size (client_master_start, - GNUNET_MESSAGE_TYPE_PSYC_MASTER_START, - struct MasterStartRequest, - NULL), - GNUNET_MQ_hd_var_size (client_slave_join, - GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN, - struct SlaveJoinRequest, - NULL), - GNUNET_MQ_hd_var_size (client_join_decision, - GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION, - struct GNUNET_PSYC_JoinDecisionMessage, - NULL), - GNUNET_MQ_hd_fixed_size (client_part_request, - GNUNET_MESSAGE_TYPE_PSYC_PART_REQUEST, - struct GNUNET_MessageHeader, - NULL), - GNUNET_MQ_hd_var_size (client_psyc_message, - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, - struct GNUNET_MessageHeader, - NULL), - GNUNET_MQ_hd_fixed_size (client_membership_store, - GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_MEMBERSHIP_STORE, - struct ChannelMembershipStoreRequest, - NULL), - GNUNET_MQ_hd_var_size (client_history_replay, - GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY, - struct GNUNET_PSYC_HistoryRequestMessage, - NULL), - GNUNET_MQ_hd_var_size (client_state_get, - GNUNET_MESSAGE_TYPE_PSYC_STATE_GET, - struct StateRequest, - NULL), - GNUNET_MQ_hd_var_size (client_state_get_prefix, - GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX, - struct StateRequest, - NULL)); - -/* end of gnunet-service-psyc.c */ diff --git a/src/psyc/psyc.conf.in b/src/psyc/psyc.conf.in deleted file mode 100644 index 764ccfa84..000000000 --- a/src/psyc/psyc.conf.in +++ /dev/null @@ -1,12 +0,0 @@ -[psyc] -START_ON_DEMAND = @START_ON_DEMAND@ -BINARY = gnunet-service-psyc - -UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-psyc.sock -UNIX_MATCH_UID = YES -UNIX_MATCH_GID = YES - -@UNIXONLY@PORT = 2115 -HOSTNAME = localhost -ACCEPT_FROM = 127.0.0.1; -ACCEPT_FROM6 = ::1; diff --git a/src/psyc/psyc.h b/src/psyc/psyc.h deleted file mode 100644 index 74bbf3edc..000000000 --- a/src/psyc/psyc.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file psyc/psyc.h - * @brief Common type definitions for the PSYC service and API. - * @author Gabor X Toth - */ - -#ifndef PSYC_H -#define PSYC_H - -#include "platform.h" -#include "gnunet_psyc_service.h" - - -int -GNUNET_PSYC_check_message_parts (uint16_t data_size, const char *data, - uint16_t *first_ptype, uint16_t *last_ptype); - -void -GNUNET_PSYC_log_message (enum GNUNET_ErrorType kind, - const struct GNUNET_MessageHeader *msg); - - -enum MessageState -{ - MSG_STATE_START = 0, - MSG_STATE_HEADER = 1, - MSG_STATE_METHOD = 2, - MSG_STATE_MODIFIER = 3, - MSG_STATE_MOD_CONT = 4, - MSG_STATE_DATA = 5, - MSG_STATE_END = 6, - MSG_STATE_CANCEL = 7, - MSG_STATE_ERROR = 8, -}; - - -enum MessageFragmentState -{ - MSG_FRAG_STATE_START = 0, - MSG_FRAG_STATE_HEADER = 1, - MSG_FRAG_STATE_DATA = 2, - MSG_FRAG_STATE_END = 3, - MSG_FRAG_STATE_CANCEL = 4, - MSG_FRAG_STATE_DROP = 5, -}; - - -GNUNET_NETWORK_STRUCT_BEGIN - - -/**** library -> service ****/ - - -struct MasterStartRequest -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYC_MASTER_START - */ - struct GNUNET_MessageHeader header; - - uint32_t policy GNUNET_PACKED; - - struct GNUNET_CRYPTO_EddsaPrivateKey channel_key; -}; - - -struct SlaveJoinRequest -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN - */ - struct GNUNET_MessageHeader header; - - uint32_t relay_count GNUNET_PACKED; - - struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key; - - struct GNUNET_CRYPTO_EcdsaPrivateKey slave_key; - - struct GNUNET_PeerIdentity origin; - - uint32_t flags GNUNET_PACKED; - - /* Followed by struct GNUNET_PeerIdentity relays[relay_count] */ - - /* Followed by struct GNUNET_MessageHeader join_msg */ -}; - - -struct ChannelMembershipStoreRequest -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_MEMBERSHIP_STORE - */ - struct GNUNET_MessageHeader header; - - uint32_t reserved GNUNET_PACKED; - - uint64_t op_id GNUNET_PACKED; - - struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; - - uint64_t announced_at GNUNET_PACKED; - - uint64_t effective_since GNUNET_PACKED; - - uint8_t did_join; -}; - - -struct HistoryRequest -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_HISTORY_REQUEST - */ - struct GNUNET_MessageHeader header; - - uint32_t reserved GNUNET_PACKED; - - /** - * ID for this operation. - */ - uint64_t op_id GNUNET_PACKED; - - uint64_t start_message_id GNUNET_PACKED; - - uint64_t end_message_id GNUNET_PACKED; - - uint64_t message_limit GNUNET_PACKED; -}; - - -struct StateRequest -{ - /** - * Types: - * - GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_STATE_GET - * - GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_STATE_GET_PREFIX - */ - struct GNUNET_MessageHeader header; - - uint32_t reserved GNUNET_PACKED; - - /** - * ID for this operation. - */ - uint64_t op_id GNUNET_PACKED; - - /* Followed by NUL-terminated name. */ -}; - - -/**** service -> library ****/ - - -GNUNET_NETWORK_STRUCT_END - -#endif diff --git a/src/psyc/psyc_api.c b/src/psyc/psyc_api.c deleted file mode 100644 index 37ea112cb..000000000 --- a/src/psyc/psyc_api.c +++ /dev/null @@ -1,1584 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file psyc/psyc_api.c - * @brief PSYC service; high-level access to the PSYC protocol - * note that clients of this API are NOT expected to - * understand the PSYC message format, only the semantics! - * Parsing (and serializing) the PSYC stream format is done - * within the implementation of the libgnunetpsyc library, - * and this API deliberately exposes as little as possible - * of the actual data stream format to the application! - * @author Gabor X Toth - */ - -#include - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_multicast_service.h" -#include "gnunet_psyc_service.h" -#include "gnunet_psyc_util_lib.h" -#include "psyc.h" - -#define LOG(kind,...) GNUNET_log_from (kind, "psyc-api",__VA_ARGS__) - - -/** - * Handle to access PSYC channel operations for both the master and slaves. - */ -struct GNUNET_PSYC_Channel -{ - /** - * Configuration to use. - */ - const struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * Client connection to the service. - */ - struct GNUNET_MQ_Handle *mq; - - /** - * Message to send on connect. - */ - struct GNUNET_MQ_Envelope *connect_env; - - /** - * Time to wait until we try to reconnect on failure. - */ - struct GNUNET_TIME_Relative reconnect_delay; - - /** - * Task for reconnecting when the listener fails. - */ - struct GNUNET_SCHEDULER_Task *reconnect_task; - - /** - * Async operations. - */ - struct GNUNET_OP_Handle *op; - - /** - * Transmission handle; - */ - struct GNUNET_PSYC_TransmitHandle *tmit; - - /** - * Receipt handle; - */ - struct GNUNET_PSYC_ReceiveHandle *recv; - - /** - * Function called after disconnected from the service. - */ - GNUNET_ContinuationCallback disconnect_cb; - - /** - * Closure for @a disconnect_cb. - */ - void *disconnect_cls; - - /** - * Are we polling for incoming messages right now? - */ - uint8_t in_receive; - - /** - * Is this a master or slave channel? - */ - uint8_t is_master; - - /** - * Is this channel in the process of disconnecting from the service? - * #GNUNET_YES or #GNUNET_NO - */ - uint8_t is_disconnecting; -}; - - -/** - * Handle for the master of a PSYC channel. - */ -struct GNUNET_PSYC_Master -{ - struct GNUNET_PSYC_Channel chn; - - GNUNET_PSYC_MasterStartCallback start_cb; - - /** - * Join request callback. - */ - GNUNET_PSYC_JoinRequestCallback join_req_cb; - - /** - * Closure for the callbacks. - */ - void *cb_cls; -}; - - -/** - * Handle for a PSYC channel slave. - */ -struct GNUNET_PSYC_Slave -{ - struct GNUNET_PSYC_Channel chn; - - GNUNET_PSYC_SlaveConnectCallback connect_cb; - - GNUNET_PSYC_JoinDecisionCallback join_dcsn_cb; - - /** - * Closure for the callbacks. - */ - void *cb_cls; -}; - - -/** - * Handle that identifies a join request. - * - * Used to match calls to #GNUNET_PSYC_JoinRequestCallback to the - * corresponding calls to GNUNET_PSYC_join_decision(). - */ -struct GNUNET_PSYC_JoinHandle -{ - struct GNUNET_PSYC_Master *mst; - struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; -}; - - -/** - * Handle for a pending PSYC transmission operation. - */ -struct GNUNET_PSYC_SlaveTransmitHandle -{ - -}; - - -struct GNUNET_PSYC_HistoryRequest -{ - /** - * Channel. - */ - struct GNUNET_PSYC_Channel *chn; - - /** - * Operation ID. - */ - uint64_t op_id; - - /** - * Message handler. - */ - struct GNUNET_PSYC_ReceiveHandle *recv; - - /** - * Function to call when the operation finished. - */ - GNUNET_ResultCallback result_cb; - - /** - * Closure for @a result_cb. - */ - void *cls; -}; - - -struct GNUNET_PSYC_StateRequest -{ - /** - * Channel. - */ - struct GNUNET_PSYC_Channel *chn; - - /** - * Operation ID. - */ - uint64_t op_id; - - /** - * State variable result callback. - */ - GNUNET_PSYC_StateVarCallback var_cb; - - /** - * Function to call when the operation finished. - */ - GNUNET_ResultCallback result_cb; - - /** - * Closure for @a result_cb. - */ - void *cls; -}; - - -static int -check_channel_result (void *cls, - const struct GNUNET_OperationResultMessage *res) -{ - return GNUNET_OK; -} - - -static void -handle_channel_result (void *cls, - const struct GNUNET_OperationResultMessage *res) -{ - struct GNUNET_PSYC_Channel *chn = cls; - - uint16_t size = ntohs (res->header.size); - if (size < sizeof (*res)) - { /* Error, message too small. */ - GNUNET_break (0); - return; - } - - uint16_t data_size = size - sizeof (*res); - const char *data = (0 < data_size) ? (void *) &res[1] : NULL; - GNUNET_OP_result (chn->op, GNUNET_ntohll (res->op_id), - GNUNET_ntohll (res->result_code), - data, data_size, NULL); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "handle_channel_result: Received result message with OP ID %" PRIu64 "\n", - GNUNET_ntohll (res->op_id)); -} - - -static void -op_recv_history_result (void *cls, int64_t result, - const void *data, uint16_t data_size) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received history replay result: %" PRId64 ".\n", result); - - struct GNUNET_PSYC_HistoryRequest *hist = cls; - - if (NULL != hist->result_cb) - hist->result_cb (hist->cls, result, data, data_size); - - GNUNET_PSYC_receive_destroy (hist->recv); - GNUNET_free (hist); -} - - -static void -op_recv_state_result (void *cls, int64_t result, - const void *data, uint16_t data_size) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received state request result: %" PRId64 ".\n", result); - - struct GNUNET_PSYC_StateRequest *sr = cls; - - if (NULL != sr->result_cb) - sr->result_cb (sr->cls, result, data, data_size); - - GNUNET_free (sr); -} - - -static int -check_channel_history_result (void *cls, - const struct GNUNET_OperationResultMessage *res) -{ - struct GNUNET_PSYC_MessageHeader * - pmsg = (struct GNUNET_PSYC_MessageHeader *) GNUNET_MQ_extract_nested_mh (res); - uint16_t size = ntohs (res->header.size); - - if ( (NULL == pmsg) || - (size < sizeof (*res) + sizeof (*pmsg)) ) - { /* Error, message too small. */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -static void -handle_channel_history_result (void *cls, - const struct GNUNET_OperationResultMessage *res) -{ - struct GNUNET_PSYC_Channel *chn = cls; - struct GNUNET_PSYC_MessageHeader * - pmsg = (struct GNUNET_PSYC_MessageHeader *) GNUNET_MQ_extract_nested_mh (res); - GNUNET_ResultCallback result_cb = NULL; - struct GNUNET_PSYC_HistoryRequest *hist = NULL; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "%p Received historic fragment for message #%" PRIu64 ".\n", - chn, - GNUNET_ntohll (pmsg->message_id)); - - if (GNUNET_YES != GNUNET_OP_get (chn->op, - GNUNET_ntohll (res->op_id), - &result_cb, (void *) &hist, NULL)) - { /* Operation not found. */ - LOG (GNUNET_ERROR_TYPE_WARNING, - "%p Replay operation not found for historic fragment of message #%" - PRIu64 ".\n", - chn, GNUNET_ntohll (pmsg->message_id)); - return; - } - - GNUNET_PSYC_receive_message (hist->recv, - (const struct GNUNET_PSYC_MessageHeader *) pmsg); -} - - -static int -check_channel_state_result (void *cls, - const struct GNUNET_OperationResultMessage *res) -{ - const struct GNUNET_MessageHeader *mod = GNUNET_MQ_extract_nested_mh (res); - uint16_t mod_size; - uint16_t size; - - if (NULL == mod) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - mod_size = ntohs (mod->size); - size = ntohs (res->header.size); - if (size - sizeof (*res) != mod_size) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -static void -handle_channel_state_result (void *cls, - const struct GNUNET_OperationResultMessage *res) -{ - struct GNUNET_PSYC_Channel *chn = cls; - - GNUNET_ResultCallback result_cb = NULL; - struct GNUNET_PSYC_StateRequest *sr = NULL; - - if (GNUNET_YES != GNUNET_OP_get (chn->op, - GNUNET_ntohll (res->op_id), - &result_cb, (void *) &sr, NULL)) - { /* Operation not found. */ - return; - } - - const struct GNUNET_MessageHeader *mod = GNUNET_MQ_extract_nested_mh (res); - if (NULL == mod) - { - GNUNET_break_op (0); - return; - } - uint16_t mod_size = ntohs (mod->size); - - switch (ntohs (mod->type)) - { - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: - { - const struct GNUNET_PSYC_MessageModifier * - pmod = (const struct GNUNET_PSYC_MessageModifier *) mod; - - const char *name = (const char *) &pmod[1]; - uint16_t name_size = ntohs (pmod->name_size); - if (0 == name_size - || mod_size - sizeof (*pmod) < name_size - || '\0' != name[name_size - 1]) - { - GNUNET_break_op (0); - return; - } - sr->var_cb (sr->cls, mod, name, name + name_size, - ntohs (pmod->header.size) - sizeof (*pmod), - ntohs (pmod->value_size)); - break; - } - - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: - sr->var_cb (sr->cls, mod, NULL, (const char *) &mod[1], - mod_size - sizeof (*mod), 0); - break; - } -} - - -static int -check_channel_message (void *cls, - const struct GNUNET_PSYC_MessageHeader *pmsg) -{ - return GNUNET_OK; -} - - -static void -handle_channel_message (void *cls, - const struct GNUNET_PSYC_MessageHeader *pmsg) -{ - struct GNUNET_PSYC_Channel *chn = cls; - - GNUNET_PSYC_receive_message (chn->recv, pmsg); -} - - -static void -handle_channel_message_ack (void *cls, - const struct GNUNET_MessageHeader *msg) -{ - struct GNUNET_PSYC_Channel *chn = cls; - - GNUNET_PSYC_transmit_got_ack (chn->tmit); -} - - -static void -handle_master_start_ack (void *cls, - const struct GNUNET_PSYC_CountersResultMessage *cres) -{ - struct GNUNET_PSYC_Master *mst = cls; - - int32_t result = ntohl (cres->result_code); - if (GNUNET_OK != result && GNUNET_NO != result) - { - LOG (GNUNET_ERROR_TYPE_ERROR, "Could not start master: %ld\n", result); - GNUNET_break (0); - /* FIXME: disconnect */ - } - if (NULL != mst->start_cb) - mst->start_cb (mst->cb_cls, result, GNUNET_ntohll (cres->max_message_id)); -} - - -static int -check_master_join_request (void *cls, - const struct GNUNET_PSYC_JoinRequestMessage *req) -{ - if ( ((sizeof (*req) + sizeof (struct GNUNET_PSYC_Message)) <= ntohs (req->header.size)) && - (NULL == GNUNET_MQ_extract_nested_mh (req)) ) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -static void -handle_master_join_request (void *cls, - const struct GNUNET_PSYC_JoinRequestMessage *req) -{ - struct GNUNET_PSYC_Master *mst = cls; - - if (NULL == mst->join_req_cb) - return; - - const struct GNUNET_PSYC_Message *join_msg = NULL; - if (sizeof (*req) + sizeof (*join_msg) <= ntohs (req->header.size)) - { - join_msg = (struct GNUNET_PSYC_Message *) GNUNET_MQ_extract_nested_mh (req); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received join_msg of type %u and size %u.\n", - ntohs (join_msg->header.type), - ntohs (join_msg->header.size)); - } - - struct GNUNET_PSYC_JoinHandle *jh = GNUNET_malloc (sizeof (*jh)); - jh->mst = mst; - jh->slave_pub_key = req->slave_pub_key; - - if (NULL != mst->join_req_cb) - mst->join_req_cb (mst->cb_cls, req, &req->slave_pub_key, join_msg, jh); -} - - -static void -handle_slave_join_ack (void *cls, - const struct GNUNET_PSYC_CountersResultMessage *cres) -{ - struct GNUNET_PSYC_Slave *slv = cls; - - int32_t result = ntohl (cres->result_code); - if (GNUNET_YES != result && GNUNET_NO != result) - { - LOG (GNUNET_ERROR_TYPE_ERROR, "Could not join slave.\n"); - GNUNET_break (0); - /* FIXME: disconnect */ - } - if (NULL != slv->connect_cb) - slv->connect_cb (slv->cb_cls, result, GNUNET_ntohll (cres->max_message_id)); -} - - -static int -check_slave_join_decision (void *cls, - const struct GNUNET_PSYC_JoinDecisionMessage *dcsn) -{ - return GNUNET_OK; -} - - -static void -handle_slave_join_decision (void *cls, - const struct GNUNET_PSYC_JoinDecisionMessage *dcsn) -{ - struct GNUNET_PSYC_Slave *slv = cls; - - struct GNUNET_PSYC_Message *pmsg = NULL; - if (ntohs (dcsn->header.size) <= sizeof (*dcsn) + sizeof (*pmsg)) - pmsg = (struct GNUNET_PSYC_Message *) &dcsn[1]; - - if (NULL != slv->join_dcsn_cb) - slv->join_dcsn_cb (slv->cb_cls, dcsn, ntohl (dcsn->is_admitted), pmsg); -} - - -static void -channel_cleanup (struct GNUNET_PSYC_Channel *chn) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "cleaning up channel %p\n", - chn); - if (NULL != chn->tmit) - { - GNUNET_PSYC_transmit_destroy (chn->tmit); - chn->tmit = NULL; - } - if (NULL != chn->recv) - { - - GNUNET_PSYC_receive_destroy (chn->recv); - chn->recv = NULL; - } - if (NULL != chn->connect_env) - { - GNUNET_MQ_discard (chn->connect_env); - chn->connect_env = NULL; - } - if (NULL != chn->mq) - { - GNUNET_MQ_destroy (chn->mq); - chn->mq = NULL; - } - if (NULL != chn->disconnect_cb) - { - chn->disconnect_cb (chn->disconnect_cls); - chn->disconnect_cb = NULL; - } - GNUNET_free (chn); -} - - -static void -handle_channel_part_ack (void *cls, - const struct GNUNET_MessageHeader *msg) -{ - struct GNUNET_PSYC_Channel *chn = cls; - - channel_cleanup (chn); -} - - -/*** MASTER ***/ - - -static void -master_connect (struct GNUNET_PSYC_Master *mst); - - -static void -master_reconnect (void *cls) -{ - master_connect (cls); -} - - -/** - * Master client disconnected from service. - * - * Reconnect after backoff period. - */ -static void -master_disconnected (void *cls, enum GNUNET_MQ_Error error) -{ - struct GNUNET_PSYC_Master *mst = cls; - struct GNUNET_PSYC_Channel *chn = &mst->chn; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Master client disconnected (%d), re-connecting\n", - (int) error); - if (NULL != chn->tmit) - { - GNUNET_PSYC_transmit_destroy (chn->tmit); - chn->tmit = NULL; - } - if (NULL != chn->mq) - { - GNUNET_MQ_destroy (chn->mq); - chn->mq = NULL; - } - chn->reconnect_task = GNUNET_SCHEDULER_add_delayed (chn->reconnect_delay, - master_reconnect, - mst); - chn->reconnect_delay = GNUNET_TIME_STD_BACKOFF (chn->reconnect_delay); -} - - -static void -master_connect (struct GNUNET_PSYC_Master *mst) -{ - struct GNUNET_PSYC_Channel *chn = &mst->chn; - - struct GNUNET_MQ_MessageHandler handlers[] = { - GNUNET_MQ_hd_fixed_size (master_start_ack, - GNUNET_MESSAGE_TYPE_PSYC_MASTER_START_ACK, - struct GNUNET_PSYC_CountersResultMessage, - mst), - GNUNET_MQ_hd_var_size (master_join_request, - GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST, - struct GNUNET_PSYC_JoinRequestMessage, - mst), - GNUNET_MQ_hd_fixed_size (channel_part_ack, - GNUNET_MESSAGE_TYPE_PSYC_PART_ACK, - struct GNUNET_MessageHeader, - chn), - GNUNET_MQ_hd_var_size (channel_message, - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, - struct GNUNET_PSYC_MessageHeader, - chn), - GNUNET_MQ_hd_fixed_size (channel_message_ack, - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK, - struct GNUNET_MessageHeader, - chn), - GNUNET_MQ_hd_var_size (channel_history_result, - GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT, - struct GNUNET_OperationResultMessage, - chn), - GNUNET_MQ_hd_var_size (channel_state_result, - GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT, - struct GNUNET_OperationResultMessage, - chn), - GNUNET_MQ_hd_var_size (channel_result, - GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE, - struct GNUNET_OperationResultMessage, - chn), - GNUNET_MQ_handler_end () - }; - - chn->mq = GNUNET_CLIENT_connect (chn->cfg, - "psyc", - handlers, - &master_disconnected, - mst); - GNUNET_assert (NULL != chn->mq); - chn->tmit = GNUNET_PSYC_transmit_create (chn->mq); - - GNUNET_MQ_send_copy (chn->mq, chn->connect_env); -} - - -/** - * Start a PSYC master channel. - * - * Will start a multicast group identified by the given ECC key. Messages - * received from group members will be given to the respective handler methods. - * If a new member wants to join a group, the "join" method handler will be - * invoked; the join handler must then generate a "join" message to approve the - * joining of the new member. The channel can also change group membership - * without explicit requests. Note that PSYC doesn't itself "understand" join - * or part messages, the respective methods must call other PSYC functions to - * inform PSYC about the meaning of the respective events. - * - * @param cfg Configuration to use (to connect to PSYC service). - * @param channel_key ECC key that will be used to sign messages for this - * PSYC session. The public key is used to identify the PSYC channel. - * Note that end-users will usually not use the private key directly, but - * rather look it up in GNS for places managed by other users, or select - * a file with the private key(s) when setting up their own channels - * FIXME: we'll likely want to use NOT the p521 curve here, but a cheaper - * one in the future. - * @param policy Channel policy specifying join and history restrictions. - * Used to automate join decisions. - * @param message_cb Function to invoke on message parts received from slaves. - * @param join_request_cb Function to invoke when a slave wants to join. - * @param master_start_cb Function to invoke after the channel master started. - * @param cls Closure for @a method and @a join_cb. - * - * @return Handle for the channel master, NULL on error. - */ -struct GNUNET_PSYC_Master * -GNUNET_PSYC_master_start (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key, - enum GNUNET_PSYC_Policy policy, - GNUNET_PSYC_MasterStartCallback start_cb, - GNUNET_PSYC_JoinRequestCallback join_request_cb, - GNUNET_PSYC_MessageCallback message_cb, - GNUNET_PSYC_MessagePartCallback message_part_cb, - void *cls) -{ - struct GNUNET_PSYC_Master *mst = GNUNET_new (struct GNUNET_PSYC_Master); - struct GNUNET_PSYC_Channel *chn = &mst->chn; - struct MasterStartRequest *req; - - chn->connect_env = GNUNET_MQ_msg (req, - GNUNET_MESSAGE_TYPE_PSYC_MASTER_START); - req->channel_key = *channel_key; - req->policy = policy; - - chn->cfg = cfg; - chn->is_master = GNUNET_YES; - chn->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; - - chn->op = GNUNET_OP_create (); - chn->recv = GNUNET_PSYC_receive_create (message_cb, message_part_cb, cls); - - mst->start_cb = start_cb; - mst->join_req_cb = join_request_cb; - mst->cb_cls = cls; - - master_connect (mst); - return mst; -} - - -/** - * Stop a PSYC master channel. - * - * @param master PSYC channel master to stop. - * @param keep_active FIXME - */ -void -GNUNET_PSYC_master_stop (struct GNUNET_PSYC_Master *mst, - int keep_active, - GNUNET_ContinuationCallback stop_cb, - void *stop_cls) -{ - struct GNUNET_PSYC_Channel *chn = &mst->chn; - struct GNUNET_MQ_Envelope *env; - - chn->is_disconnecting = GNUNET_YES; - chn->disconnect_cb = stop_cb; - chn->disconnect_cls = stop_cls; - env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_PSYC_PART_REQUEST); - GNUNET_MQ_send (chn->mq, env); -} - - -/** - * Function to call with the decision made for a join request. - * - * Must be called once and only once in response to an invocation of the - * #GNUNET_PSYC_JoinCallback. - * - * @param jh Join request handle. - * @param is_admitted #GNUNET_YES if the join is approved, - * #GNUNET_NO if it is disapproved, - * #GNUNET_SYSERR if we cannot answer the request. - * @param relay_count Number of relays given. - * @param relays Array of suggested peers that might be useful relays to use - * when joining the multicast group (essentially a list of peers that - * are already part of the multicast group and might thus be willing - * to help with routing). If empty, only this local peer (which must - * be the multicast origin) is a good candidate for building the - * multicast tree. Note that it is unnecessary to specify our own - * peer identity in this array. - * @param join_resp Application-dependent join response message. - * - * @return #GNUNET_OK on success, - * #GNUNET_SYSERR if the message is too large. - */ -int -GNUNET_PSYC_join_decision (struct GNUNET_PSYC_JoinHandle *jh, - int is_admitted, - uint32_t relay_count, - const struct GNUNET_PeerIdentity *relays, - const struct GNUNET_PSYC_Message *join_resp) -{ - struct GNUNET_PSYC_Channel *chn = &jh->mst->chn; - struct GNUNET_PSYC_JoinDecisionMessage *dcsn; - uint16_t join_resp_size - = (NULL != join_resp) ? ntohs (join_resp->header.size) : 0; - uint16_t relay_size = relay_count * sizeof (*relays); - - if (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD - < sizeof (*dcsn) + relay_size + join_resp_size) - return GNUNET_SYSERR; - - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (dcsn, relay_size + join_resp_size, - GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION); - dcsn->is_admitted = htonl (is_admitted); - dcsn->slave_pub_key = jh->slave_pub_key; - - if (0 < join_resp_size) - GNUNET_memcpy (&dcsn[1], join_resp, join_resp_size); - - GNUNET_MQ_send (chn->mq, env); - GNUNET_free (jh); - return GNUNET_OK; -} - - -/** - * Send a message to call a method to all members in the PSYC channel. - * - * @param master Handle to the PSYC channel. - * @param method_name Which method should be invoked. - * @param notify_mod Function to call to obtain modifiers. - * @param notify_data Function to call to obtain fragments of the data. - * @param notify_cls Closure for @a notify_mod and @a notify_data. - * @param flags Flags for the message being transmitted. - * - * @return Transmission handle, NULL on error (i.e. more than one request queued). - */ -struct GNUNET_PSYC_MasterTransmitHandle * -GNUNET_PSYC_master_transmit (struct GNUNET_PSYC_Master *mst, - const char *method_name, - GNUNET_PSYC_TransmitNotifyModifier notify_mod, - GNUNET_PSYC_TransmitNotifyData notify_data, - void *notify_cls, - enum GNUNET_PSYC_MasterTransmitFlags flags) -{ - if (GNUNET_OK - == GNUNET_PSYC_transmit_message (mst->chn.tmit, method_name, NULL, - notify_mod, notify_data, notify_cls, - flags)) - return (struct GNUNET_PSYC_MasterTransmitHandle *) mst->chn.tmit; - else - return NULL; -} - - -/** - * Resume transmission to the channel. - * - * @param tmit Handle of the request that is being resumed. - */ -void -GNUNET_PSYC_master_transmit_resume (struct GNUNET_PSYC_MasterTransmitHandle *tmit) -{ - GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) tmit); -} - - -/** - * Abort transmission request to the channel. - * - * @param tmit Handle of the request that is being aborted. - */ -void -GNUNET_PSYC_master_transmit_cancel (struct GNUNET_PSYC_MasterTransmitHandle *tmit) -{ - GNUNET_PSYC_transmit_cancel ((struct GNUNET_PSYC_TransmitHandle *) tmit); -} - - -/** - * Convert a channel @a master to a @e channel handle to access the @e channel - * APIs. - * - * @param master Channel master handle. - * - * @return Channel handle, valid for as long as @a master is valid. - */ -struct GNUNET_PSYC_Channel * -GNUNET_PSYC_master_get_channel (struct GNUNET_PSYC_Master *master) -{ - return &master->chn; -} - - -/*** SLAVE ***/ - - -static void -slave_connect (struct GNUNET_PSYC_Slave *slv); - - -static void -slave_reconnect (void *cls) -{ - slave_connect (cls); -} - - -/** - * Slave client disconnected from service. - * - * Reconnect after backoff period. - */ -static void -slave_disconnected (void *cls, - enum GNUNET_MQ_Error error) -{ - struct GNUNET_PSYC_Slave *slv = cls; - struct GNUNET_PSYC_Channel *chn = &slv->chn; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Slave client disconnected (%d), re-connecting\n", - (int) error); - if (NULL != chn->tmit) - { - GNUNET_PSYC_transmit_destroy (chn->tmit); - chn->tmit = NULL; - } - if (NULL != chn->mq) - { - GNUNET_MQ_destroy (chn->mq); - chn->mq = NULL; - } - chn->reconnect_task = GNUNET_SCHEDULER_add_delayed (chn->reconnect_delay, - &slave_reconnect, - slv); - chn->reconnect_delay = GNUNET_TIME_STD_BACKOFF (chn->reconnect_delay); -} - - -static void -slave_connect (struct GNUNET_PSYC_Slave *slv) -{ - struct GNUNET_PSYC_Channel *chn = &slv->chn; - - struct GNUNET_MQ_MessageHandler handlers[] = { - GNUNET_MQ_hd_fixed_size (slave_join_ack, - GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN_ACK, - struct GNUNET_PSYC_CountersResultMessage, - slv), - GNUNET_MQ_hd_var_size (slave_join_decision, - GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION, - struct GNUNET_PSYC_JoinDecisionMessage, - slv), - GNUNET_MQ_hd_fixed_size (channel_part_ack, - GNUNET_MESSAGE_TYPE_PSYC_PART_ACK, - struct GNUNET_MessageHeader, - chn), - GNUNET_MQ_hd_var_size (channel_message, - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, - struct GNUNET_PSYC_MessageHeader, - chn), - GNUNET_MQ_hd_fixed_size (channel_message_ack, - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK, - struct GNUNET_MessageHeader, - chn), - GNUNET_MQ_hd_var_size (channel_history_result, - GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT, - struct GNUNET_OperationResultMessage, - chn), - GNUNET_MQ_hd_var_size (channel_state_result, - GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT, - struct GNUNET_OperationResultMessage, - chn), - GNUNET_MQ_hd_var_size (channel_result, - GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE, - struct GNUNET_OperationResultMessage, - chn), - GNUNET_MQ_handler_end () - }; - - chn->mq = GNUNET_CLIENT_connect (chn->cfg, - "psyc", - handlers, - &slave_disconnected, - slv); - if (NULL == chn->mq) - { - chn->reconnect_task = GNUNET_SCHEDULER_add_delayed (chn->reconnect_delay, - &slave_reconnect, - slv); - chn->reconnect_delay = GNUNET_TIME_STD_BACKOFF (chn->reconnect_delay); - return; - } - chn->tmit = GNUNET_PSYC_transmit_create (chn->mq); - - GNUNET_MQ_send_copy (chn->mq, chn->connect_env); -} - - -/** - * Join a PSYC channel. - * - * The entity joining is always the local peer. The user must immediately use - * the GNUNET_PSYC_slave_transmit() functions to transmit a @e join_msg to the - * channel; if the join request succeeds, the channel state (and @e recent - * method calls) will be replayed to the joining member. There is no explicit - * notification on failure (as the channel may simply take days to approve, - * and disapproval is simply being ignored). - * - * @param cfg - * Configuration to use. - * @param channel_key ECC public key that identifies the channel we wish to join. - * @param slave_key ECC private-public key pair that identifies the slave, and - * used by multicast to sign the join request and subsequent unicast - * requests sent to the master. - * @param origin Peer identity of the origin. - * @param relay_count Number of peers in the @a relays array. - * @param relays Peer identities of members of the multicast group, which serve - * as relays and used to join the group at. - * @param message_cb Function to invoke on message parts received from the - * channel, typically at least contains method handlers for @e join and - * @e part. - * @param slave_connect_cb Function invoked once we have connected to the - * PSYC service. - * @param join_decision_cb Function invoked once we have received a join - * decision. - * @param cls Closure for @a message_cb and @a slave_joined_cb. - * @param method_name Method name for the join request. - * @param env Environment containing transient variables for the request, or NULL. - * @param data Payload for the join message. - * @param data_size Number of bytes in @a data. - * - * @return Handle for the slave, NULL on error. - */ -struct GNUNET_PSYC_Slave * -GNUNET_PSYC_slave_join (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_pub_key, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key, - enum GNUNET_PSYC_SlaveJoinFlags flags, - const struct GNUNET_PeerIdentity *origin, - uint32_t relay_count, - const struct GNUNET_PeerIdentity *relays, - GNUNET_PSYC_MessageCallback message_cb, - GNUNET_PSYC_MessagePartCallback message_part_cb, - GNUNET_PSYC_SlaveConnectCallback connect_cb, - GNUNET_PSYC_JoinDecisionCallback join_decision_cb, - void *cls, - const struct GNUNET_PSYC_Message *join_msg) -{ - struct GNUNET_PSYC_Slave *slv = GNUNET_malloc (sizeof (*slv)); - struct GNUNET_PSYC_Channel *chn = &slv->chn; - uint16_t relay_size = relay_count * sizeof (*relays); - uint16_t join_msg_size; - if (NULL == join_msg) - join_msg_size = 0; - else - join_msg_size = ntohs (join_msg->header.size); - - struct SlaveJoinRequest *req; - chn->connect_env = GNUNET_MQ_msg_extra (req, relay_size + join_msg_size, - GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN); - req->channel_pub_key = *channel_pub_key; - req->slave_key = *slave_key; - req->origin = *origin; - req->relay_count = htonl (relay_count); - req->flags = htonl (flags); - - if (0 < relay_size) - GNUNET_memcpy (&req[1], relays, relay_size); - - if (NULL != join_msg) - GNUNET_memcpy ((char *) &req[1] + relay_size, join_msg, join_msg_size); - - chn->cfg = cfg; - chn->is_master = GNUNET_NO; - chn->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; - - chn->op = GNUNET_OP_create (); - chn->recv = GNUNET_PSYC_receive_create (message_cb, message_part_cb, cls); - - slv->connect_cb = connect_cb; - slv->join_dcsn_cb = join_decision_cb; - slv->cb_cls = cls; - - slave_connect (slv); - return slv; -} - - -/** - * Part a PSYC channel. - * - * Will terminate the connection to the PSYC service. Polite clients should - * first explicitly send a part request (via GNUNET_PSYC_slave_transmit()). - * - * @param slave Slave handle. - */ -void -GNUNET_PSYC_slave_part (struct GNUNET_PSYC_Slave *slv, - int keep_active, - GNUNET_ContinuationCallback part_cb, - void *part_cls) -{ - struct GNUNET_PSYC_Channel *chn = &slv->chn; - struct GNUNET_MQ_Envelope *env; - - chn->is_disconnecting = GNUNET_YES; - chn->disconnect_cb = part_cb; - chn->disconnect_cls = part_cls; - env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_PSYC_PART_REQUEST); - GNUNET_MQ_send (chn->mq, env); -} - - -/** - * Request a message to be sent to the channel master. - * - * @param slave Slave handle. - * @param method_name Which (PSYC) method should be invoked (on host). - * @param notify_mod Function to call to obtain modifiers. - * @param notify_data Function to call to obtain fragments of the data. - * @param notify_cls Closure for @a notify. - * @param flags Flags for the message being transmitted. - * - * @return Transmission handle, NULL on error (i.e. more than one request - * queued). - */ -struct GNUNET_PSYC_SlaveTransmitHandle * -GNUNET_PSYC_slave_transmit (struct GNUNET_PSYC_Slave *slv, - const char *method_name, - GNUNET_PSYC_TransmitNotifyModifier notify_mod, - GNUNET_PSYC_TransmitNotifyData notify_data, - void *notify_cls, - enum GNUNET_PSYC_SlaveTransmitFlags flags) - -{ - if (GNUNET_OK - == GNUNET_PSYC_transmit_message (slv->chn.tmit, method_name, NULL, - notify_mod, notify_data, notify_cls, - flags)) - return (struct GNUNET_PSYC_SlaveTransmitHandle *) slv->chn.tmit; - else - return NULL; -} - - -/** - * Resume transmission to the master. - * - * @param tmit Handle of the request that is being resumed. - */ -void -GNUNET_PSYC_slave_transmit_resume (struct GNUNET_PSYC_SlaveTransmitHandle *tmit) -{ - GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) tmit); -} - - -/** - * Abort transmission request to master. - * - * @param tmit Handle of the request that is being aborted. - */ -void -GNUNET_PSYC_slave_transmit_cancel (struct GNUNET_PSYC_SlaveTransmitHandle *tmit) -{ - GNUNET_PSYC_transmit_cancel ((struct GNUNET_PSYC_TransmitHandle *) tmit); -} - - -/** - * Convert @a slave to a @e channel handle to access the @e channel APIs. - * - * @param slv Slave handle. - * - * @return Channel handle, valid for as long as @a slave is valid. - */ -struct GNUNET_PSYC_Channel * -GNUNET_PSYC_slave_get_channel (struct GNUNET_PSYC_Slave *slv) -{ - return &slv->chn; -} - - -/** - * Add a slave to the channel's membership list. - * - * Note that this will NOT generate any PSYC traffic, it will merely update the - * local database to modify how we react to membership test queries. - * The channel master still needs to explicitly transmit a @e join message to - * notify other channel members and they then also must still call this function - * in their respective methods handling the @e join message. This way, how @e - * join and @e part operations are exactly implemented is still up to the - * application; for example, there might be a @e part_all method to kick out - * everyone. - * - * Note that channel slaves are explicitly trusted to execute such methods - * correctly; not doing so correctly will result in either denying other slaves - * access or offering access to channel data to non-members. - * - * @param chn - * Channel handle. - * @param slave_pub_key - * Identity of channel slave to add. - * @param announced_at - * ID of the message that announced the membership change. - * @param effective_since - * Addition of slave is in effect since this message ID. - * @param result_cb - * Function to call with the result of the operation. - * The @e result_code argument is #GNUNET_OK on success, or - * #GNUNET_SYSERR on error. In case of an error, the @e data argument - * can contain an optional error message. - * @param cls - * Closure for @a result_cb. - */ -void -GNUNET_PSYC_channel_slave_add (struct GNUNET_PSYC_Channel *chn, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key, - uint64_t announced_at, - uint64_t effective_since, - GNUNET_ResultCallback result_cb, - void *cls) -{ - struct ChannelMembershipStoreRequest *req; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_MEMBERSHIP_STORE); - req->slave_pub_key = *slave_pub_key; - req->announced_at = GNUNET_htonll (announced_at); - req->effective_since = GNUNET_htonll (effective_since); - req->did_join = GNUNET_YES; - req->op_id = GNUNET_htonll (GNUNET_OP_add (chn->op, result_cb, cls, NULL)); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "GNUNET_PSYC_channel_slave_add, OP ID: %" PRIu64 "\n", - GNUNET_ntohll (req->op_id)); - GNUNET_MQ_send (chn->mq, env); -} - - -/** - * Remove a slave from the channel's membership list. - * - * Note that this will NOT generate any PSYC traffic, it will merely update the - * local database to modify how we react to membership test queries. - * The channel master still needs to explicitly transmit a @e part message to - * notify other channel members and they then also must still call this function - * in their respective methods handling the @e part message. This way, how - * @e join and @e part operations are exactly implemented is still up to the - * application; for example, there might be a @e part_all message to kick out - * everyone. - * - * Note that channel members are explicitly trusted to perform these - * operations correctly; not doing so correctly will result in either - * denying members access or offering access to channel data to - * non-members. - * - * @param chn - * Channel handle. - * @param slave_pub_key - * Identity of channel slave to remove. - * @param announced_at - * ID of the message that announced the membership change. - * @param result_cb - * Function to call with the result of the operation. - * The @e result_code argument is #GNUNET_OK on success, or - * #GNUNET_SYSERR on error. In case of an error, the @e data argument - * can contain an optional error message. - * @param cls - * Closure for @a result_cb. - */ -void -GNUNET_PSYC_channel_slave_remove (struct GNUNET_PSYC_Channel *chn, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key, - uint64_t announced_at, - GNUNET_ResultCallback result_cb, - void *cls) -{ - struct ChannelMembershipStoreRequest *req; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_MEMBERSHIP_STORE); - req->slave_pub_key = *slave_pub_key; - req->announced_at = GNUNET_htonll (announced_at); - req->did_join = GNUNET_NO; - req->op_id = GNUNET_htonll (GNUNET_OP_add (chn->op, result_cb, cls, NULL)); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "GNUNET_PSYC_channel_slave_remove, OP ID: %" PRIu64 "\n", - GNUNET_ntohll (req->op_id)); - GNUNET_MQ_send (chn->mq, env); -} - - -static struct GNUNET_PSYC_HistoryRequest * -channel_history_replay (struct GNUNET_PSYC_Channel *chn, - uint64_t start_message_id, - uint64_t end_message_id, - uint64_t message_limit, - const char *method_prefix, - uint32_t flags, - GNUNET_PSYC_MessageCallback message_cb, - GNUNET_PSYC_MessagePartCallback message_part_cb, - GNUNET_ResultCallback result_cb, - void *cls) -{ - struct GNUNET_PSYC_HistoryRequestMessage *req; - struct GNUNET_PSYC_HistoryRequest *hist = GNUNET_malloc (sizeof (*hist)); - hist->chn = chn; - hist->recv = GNUNET_PSYC_receive_create (message_cb, message_part_cb, cls); - hist->result_cb = result_cb; - hist->cls = cls; - hist->op_id = GNUNET_OP_add (chn->op, op_recv_history_result, hist, NULL); - - GNUNET_assert (NULL != method_prefix); - uint16_t method_size = strnlen (method_prefix, - GNUNET_MAX_MESSAGE_SIZE - - sizeof (*req)) + 1; - GNUNET_assert ('\0' == method_prefix[method_size - 1]); - - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (req, method_size, - GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY); - req->start_message_id = GNUNET_htonll (start_message_id); - req->end_message_id = GNUNET_htonll (end_message_id); - req->message_limit = GNUNET_htonll (message_limit); - req->flags = htonl (flags); - req->op_id = GNUNET_htonll (hist->op_id); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "channel_history_replay, OP ID: %" PRIu64 "\n", - GNUNET_ntohll (req->op_id)); - GNUNET_memcpy (&req[1], method_prefix, method_size); - - GNUNET_MQ_send (chn->mq, env); - return hist; -} - - -/** - * Request to replay a part of the message history of the channel. - * - * Historic messages (but NOT the state at the time) will be replayed and given - * to the normal method handlers with a #GNUNET_PSYC_MESSAGE_HISTORIC flag set. - * - * Messages are retrieved from the local PSYCstore if available, - * otherwise requested from the network. - * - * @param channel - * Which channel should be replayed? - * @param start_message_id - * Earliest interesting point in history. - * @param end_message_id - * Last (inclusive) interesting point in history. - * @param method_prefix - * Retrieve only messages with a matching method prefix. - * @param flags - * OR'ed enum GNUNET_PSYC_HistoryReplayFlags - * @param result_cb - * Function to call when the requested history has been fully replayed. - * @param cls - * Closure for the callbacks. - * - * @return Handle to cancel history replay operation. - */ -struct GNUNET_PSYC_HistoryRequest * -GNUNET_PSYC_channel_history_replay (struct GNUNET_PSYC_Channel *chn, - uint64_t start_message_id, - uint64_t end_message_id, - const char *method_prefix, - uint32_t flags, - GNUNET_PSYC_MessageCallback message_cb, - GNUNET_PSYC_MessagePartCallback message_part_cb, - GNUNET_ResultCallback result_cb, - void *cls) -{ - return channel_history_replay (chn, start_message_id, end_message_id, 0, - method_prefix, flags, - message_cb, message_part_cb, result_cb, cls); -} - - -/** - * Request to replay the latest messages from the message history of the channel. - * - * Historic messages (but NOT the state at the time) will be replayed (given to - * the normal method handlers) if available and if access is permitted. - * - * @param channel - * Which channel should be replayed? - * @param message_limit - * Maximum number of messages to replay. - * @param method_prefix - * Retrieve only messages with a matching method prefix. - * Use NULL or "" to retrieve all. - * @param flags - * OR'ed enum GNUNET_PSYC_HistoryReplayFlags - * @param result_cb - * Function to call when the requested history has been fully replayed. - * @param cls - * Closure for the callbacks. - * - * @return Handle to cancel history replay operation. - */ -struct GNUNET_PSYC_HistoryRequest * -GNUNET_PSYC_channel_history_replay_latest (struct GNUNET_PSYC_Channel *chn, - uint64_t message_limit, - const char *method_prefix, - uint32_t flags, - GNUNET_PSYC_MessageCallback message_cb, - GNUNET_PSYC_MessagePartCallback message_part_cb, - GNUNET_ResultCallback result_cb, - void *cls) -{ - return channel_history_replay (chn, 0, 0, message_limit, method_prefix, flags, - message_cb, message_part_cb, result_cb, cls); -} - - -void -GNUNET_PSYC_channel_history_replay_cancel (struct GNUNET_PSYC_Channel *channel, - struct GNUNET_PSYC_HistoryRequest *hist) -{ - GNUNET_PSYC_receive_destroy (hist->recv); - GNUNET_OP_remove (hist->chn->op, hist->op_id); - GNUNET_free (hist); -} - - -/** - * Retrieve the best matching channel state variable. - * - * If the requested variable name is not present in the state, the nearest - * less-specific name is matched; for example, requesting "_a_b" will match "_a" - * if "_a_b" does not exist. - * - * @param channel - * Channel handle. - * @param full_name - * Full name of the requested variable. - * The actual variable returned might have a shorter name. - * @param var_cb - * Function called once when a matching state variable is found. - * Not called if there's no matching state variable. - * @param result_cb - * Function called after the operation finished. - * (i.e. all state variables have been returned via @a state_cb) - * @param cls - * Closure for the callbacks. - */ -static struct GNUNET_PSYC_StateRequest * -channel_state_get (struct GNUNET_PSYC_Channel *chn, - uint16_t type, const char *name, - GNUNET_PSYC_StateVarCallback var_cb, - GNUNET_ResultCallback result_cb, void *cls) -{ - struct StateRequest *req; - struct GNUNET_PSYC_StateRequest *sr = GNUNET_malloc (sizeof (*sr)); - sr->chn = chn; - sr->var_cb = var_cb; - sr->result_cb = result_cb; - sr->cls = cls; - sr->op_id = GNUNET_OP_add (chn->op, op_recv_state_result, sr, NULL); - - GNUNET_assert (NULL != name); - size_t name_size = strnlen (name, GNUNET_MAX_MESSAGE_SIZE - - sizeof (*req)) + 1; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (req, name_size, type); - req->op_id = GNUNET_htonll (sr->op_id); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "channel_state_get, OP ID: %" PRIu64 "\n", - GNUNET_ntohll (req->op_id)); - - GNUNET_memcpy (&req[1], name, name_size); - - GNUNET_MQ_send (chn->mq, env); - return sr; -} - - -/** - * Retrieve the best matching channel state variable. - * - * If the requested variable name is not present in the state, the nearest - * less-specific name is matched; for example, requesting "_a_b" will match "_a" - * if "_a_b" does not exist. - * - * @param channel - * Channel handle. - * @param full_name - * Full name of the requested variable. - * The actual variable returned might have a shorter name. - * @param var_cb - * Function called once when a matching state variable is found. - * Not called if there's no matching state variable. - * @param result_cb - * Function called after the operation finished. - * (i.e. all state variables have been returned via @a state_cb) - * @param cls - * Closure for the callbacks. - */ -struct GNUNET_PSYC_StateRequest * -GNUNET_PSYC_channel_state_get (struct GNUNET_PSYC_Channel *chn, - const char *full_name, - GNUNET_PSYC_StateVarCallback var_cb, - GNUNET_ResultCallback result_cb, - void *cls) -{ - return channel_state_get (chn, GNUNET_MESSAGE_TYPE_PSYC_STATE_GET, - full_name, var_cb, result_cb, cls); - -} - - -/** - * Return all channel state variables whose name matches a given prefix. - * - * A name matches if it starts with the given @a name_prefix, thus requesting - * the empty prefix ("") will match all values; requesting "_a_b" will also - * return values stored under "_a_b_c". - * - * The @a state_cb is invoked on all matching state variables asynchronously, as - * the state is stored in and retrieved from the PSYCstore, - * - * @param channel - * Channel handle. - * @param name_prefix - * Prefix of the state variable name to match. - * @param var_cb - * Function called once when a matching state variable is found. - * Not called if there's no matching state variable. - * @param result_cb - * Function called after the operation finished. - * (i.e. all state variables have been returned via @a state_cb) - * @param cls - * Closure for the callbacks. - */ -struct GNUNET_PSYC_StateRequest * -GNUNET_PSYC_channel_state_get_prefix (struct GNUNET_PSYC_Channel *chn, - const char *name_prefix, - GNUNET_PSYC_StateVarCallback var_cb, - GNUNET_ResultCallback result_cb, - void *cls) -{ - return channel_state_get (chn, GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX, - name_prefix, var_cb, result_cb, cls); -} - - -/** - * Cancel a state request operation. - * - * @param sr - * Handle for the operation to cancel. - */ -void -GNUNET_PSYC_channel_state_get_cancel (struct GNUNET_PSYC_StateRequest *sr) -{ - GNUNET_OP_remove (sr->chn->op, sr->op_id); - GNUNET_free (sr); -} - -/* end of psyc_api.c */ diff --git a/src/psyc/psyc_test_lib.h b/src/psyc/psyc_test_lib.h deleted file mode 100644 index 0ad991061..000000000 --- a/src/psyc/psyc_test_lib.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file psyc/test_psyc_api_join.c - * @brief library for writing psyc tests - * @author xrs - */ - -#define MAX_TESTBED_OPS 32 - -struct pctx -{ - int idx; - - struct GNUNET_TESTBED_Peer *testbed_peer; - - const struct GNUNET_PeerIdentity *peer_id; - - const struct GNUNET_PeerIdentity *peer_id_master; - - /** - * Used to simulate egos (not peerid) - */ - const struct GNUNET_CRYPTO_EcdsaPrivateKey *id_key; - - const struct GNUNET_CRYPTO_EcdsaPublicKey *id_pub_key; - - /** - * Used to store either GNUNET_PSYC_Master or GNUNET_PSYC_Slave handle - */ - void *psyc; - - struct GNUNET_PSYC_Channel *channel; - - const struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key; - - struct GNUNET_CRYPTO_EddsaPublicKey *channel_pub_key; - - int test_ok; -}; - -static struct GNUNET_SCHEDULER_Task *timeout_task_id; - -static int result = GNUNET_SYSERR; - -static struct GNUNET_TESTBED_Operation *op[MAX_TESTBED_OPS]; - -static int op_cnt = 0; - diff --git a/src/psyc/test_psyc.c b/src/psyc/test_psyc.c deleted file mode 100644 index b6e27bbab..000000000 --- a/src/psyc/test_psyc.c +++ /dev/null @@ -1,1018 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file psyc/test_psyc.c - * @brief Tests for the PSYC API. - * @author Gabor X Toth - * @author Christian Grothoff - */ - -#include - -#include "platform.h" -#include "gnunet_crypto_lib.h" -#include "gnunet_common.h" -#include "gnunet_util_lib.h" -#include "gnunet_testing_lib.h" -#include "gnunet_psyc_util_lib.h" -#include "gnunet_psyc_service.h" - -#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) - -/** - * Return value from 'main'. - */ -static int res; - -static const struct GNUNET_CONFIGURATION_Handle *cfg; - -static struct GNUNET_PeerIdentity this_peer; - -/** - * Handle for task for timeout termination. - */ -static struct GNUNET_SCHEDULER_Task * end_badly_task; - -static struct GNUNET_PSYC_Master *mst; -static struct GNUNET_PSYC_Slave *slv; - -static struct GNUNET_PSYC_Channel *mst_chn, *slv_chn; - -static struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key; -static struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key; - -static struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key; -static struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; - -struct TransmitClosure -{ - struct GNUNET_PSYC_MasterTransmitHandle *mst_tmit; - struct GNUNET_PSYC_SlaveTransmitHandle *slv_tmit; - struct GNUNET_PSYC_Environment *env; - struct GNUNET_PSYC_Modifier *mod; - char *data[16]; - const char *mod_value; - size_t mod_value_size; - uint8_t data_delay[16]; - uint8_t data_count; - uint8_t paused; - uint8_t n; -}; - -static struct TransmitClosure *tmit; - -static uint8_t join_req_count, end_count; - -enum -{ - TEST_NONE = 0, - TEST_MASTER_START = 1, - TEST_SLAVE_JOIN_REJECT = 2, - TEST_SLAVE_JOIN_ACCEPT = 3, - TEST_SLAVE_ADD = 4, - TEST_SLAVE_REMOVE = 5, - TEST_SLAVE_TRANSMIT = 6, - TEST_MASTER_TRANSMIT = 7, - TEST_MASTER_HISTORY_REPLAY_LATEST = 8, - TEST_SLAVE_HISTORY_REPLAY_LATEST = 9, - TEST_MASTER_HISTORY_REPLAY = 10, - TEST_SLAVE_HISTORY_REPLAY = 11, - TEST_MASTER_STATE_GET = 12, - TEST_SLAVE_STATE_GET = 13, - TEST_MASTER_STATE_GET_PREFIX = 14, - TEST_SLAVE_STATE_GET_PREFIX = 15, -} test; - - -static void -master_transmit (); - -static void -master_history_replay_latest (); - - -static void -master_stopped (void *cls) -{ - if (NULL != tmit) - { - GNUNET_PSYC_env_destroy (tmit->env); - GNUNET_free (tmit); - tmit = NULL; - } - GNUNET_SCHEDULER_shutdown (); -} - - -static void -slave_parted (void *cls) -{ - if (NULL != mst) - { - GNUNET_PSYC_master_stop (mst, GNUNET_NO, &master_stopped, NULL); - mst = NULL; - } - else - master_stopped (NULL); -} - - -/** - * Clean up all resources used. - */ -static void -cleanup () -{ - if (NULL != slv) - { - GNUNET_PSYC_slave_part (slv, GNUNET_NO, &slave_parted, NULL); - slv = NULL; - } - else - slave_parted (NULL); -} - - -/** - * Terminate the test case (failure). - * - * @param cls NULL - */ -static void -end_badly (void *cls) -{ - res = 1; - cleanup (); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test FAILED.\n"); -} - - -/** - * Terminate the test case (success). - * - * @param cls NULL - */ -static void -end_normally (void *cls) -{ - res = 0; - cleanup (); - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Test PASSED.\n"); -} - - -/** - * Finish the test case (successfully). - */ -static void -end () -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Ending tests.\n"); - - if (end_badly_task != NULL) - { - GNUNET_SCHEDULER_cancel (end_badly_task); - end_badly_task = NULL; - } - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, - &end_normally, NULL); -} - - -static void -master_message_cb (void *cls, const struct GNUNET_PSYC_MessageHeader *msg) -{ - GNUNET_assert (NULL != msg); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%d: Master got PSYC message fragment of size %u " - "belonging to message ID %" PRIu64 " with flags %x\n", - test, ntohs (msg->header.size), - GNUNET_ntohll (msg->message_id), ntohl (msg->flags)); - // FIXME -} - - -static void -master_message_part_cb (void *cls, const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg) -{ - GNUNET_assert (NULL != msg && NULL != pmsg); - - uint64_t message_id = GNUNET_ntohll (msg->message_id); - uint32_t flags = ntohl (msg->flags); - - uint16_t type = ntohs (pmsg->type); - uint16_t size = ntohs (pmsg->size); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%d: Master got message part of type %u and size %u " - "belonging to message ID %" PRIu64 " with flags %x\n", - test, type, size, message_id, flags); - - switch (test) - { - case TEST_SLAVE_TRANSMIT: - if (GNUNET_PSYC_MESSAGE_REQUEST != flags) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Test #%d: Unexpected request flags: %x" PRIu32 "\n", - test, flags); - GNUNET_assert (0); - return; - } - // FIXME: check rest of message - - if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END == type) - master_transmit (); - break; - - case TEST_MASTER_TRANSMIT: - if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END == type && 2 == ++end_count) - master_history_replay_latest (); - break; - - case TEST_MASTER_HISTORY_REPLAY: - case TEST_MASTER_HISTORY_REPLAY_LATEST: - if (GNUNET_PSYC_MESSAGE_HISTORIC != flags) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Test #%d: Unexpected flags for historic message: %x" PRIu32 "\n", - test, flags); - GNUNET_assert (0); - return; - } - break; - - default: - GNUNET_assert (0); - } -} - - -static void -slave_message_cb (void *cls, const struct GNUNET_PSYC_MessageHeader *msg) -{ - GNUNET_assert (NULL != msg); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%d: Slave got PSYC message fragment of size %u " - "belonging to message ID %" PRIu64 " with flags %x\n", - test, ntohs (msg->header.size), - GNUNET_ntohll (msg->message_id), ntohl (msg->flags)); - // FIXME -} - - -static void -slave_message_part_cb (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg) -{ - GNUNET_assert (NULL != msg && NULL != pmsg); - - uint64_t message_id = GNUNET_ntohll (msg->message_id); - uint32_t flags = ntohl (msg->flags); - - uint16_t type = ntohs (pmsg->type); - uint16_t size = ntohs (pmsg->size); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%d: Slave got message part of type %u and size %u " - "belonging to message ID %" PRIu64 " with flags %x\n", - test, type, size, message_id, flags); - - switch (test) - { - case TEST_MASTER_TRANSMIT: - if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END == type && 2 == ++end_count) - master_history_replay_latest (); - break; - - case TEST_SLAVE_HISTORY_REPLAY: - case TEST_SLAVE_HISTORY_REPLAY_LATEST: - if (GNUNET_PSYC_MESSAGE_HISTORIC != flags) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Test #%d: Unexpected flags for historic message: %x" PRIu32 "\n", - test, flags); - GNUNET_assert (0); - return; - } - break; - - default: - GNUNET_assert (0); - } -} - - -static void -state_get_var (void *cls, const struct GNUNET_MessageHeader *mod, - const char *name, const void *value, - uint32_t value_size, uint32_t full_value_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Got state var: %s\n%.*s\n", - name, - (int) value_size, - (const char *) value); -} - - -/*** Slave state_get_prefix() ***/ - -static void -slave_state_get_prefix_result (void *cls, int64_t result, - const void *err_msg, uint16_t err_msg_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%d: slave_state_get_prefix:\t%" PRId64 " (%.*s)\n", - test, result, - (int) err_msg_size, - (const char *) err_msg); - // FIXME: GNUNET_assert (2 == result); - end (); -} - - -static void -slave_state_get_prefix () -{ - test = TEST_SLAVE_STATE_GET_PREFIX; - GNUNET_PSYC_channel_state_get_prefix (slv_chn, "_foo", state_get_var, - slave_state_get_prefix_result, NULL); -} - - -/*** Master state_get_prefix() ***/ - - -static void -master_state_get_prefix_result (void *cls, int64_t result, - const void *err_msg, uint16_t err_msg_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%d: master_state_get_prefix:\t%" PRId64 " (%s)\n", - test, result, (char *) err_msg); - // FIXME: GNUNET_assert (2 == result); - slave_state_get_prefix (); -} - - -static void -master_state_get_prefix () -{ - test = TEST_MASTER_STATE_GET_PREFIX; - GNUNET_PSYC_channel_state_get_prefix (mst_chn, "_foo", state_get_var, - master_state_get_prefix_result, NULL); -} - - -/*** Slave state_get() ***/ - - -static void -slave_state_get_result (void *cls, int64_t result, - const void *err_msg, uint16_t err_msg_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%d: slave_state_get:\t%" PRId64 " (%.*s)\n", - test, result, err_msg_size, (char *) err_msg); - // FIXME: GNUNET_assert (2 == result); - master_state_get_prefix (); -} - - -static void -slave_state_get () -{ - test = TEST_SLAVE_STATE_GET; - GNUNET_PSYC_channel_state_get (slv_chn, "_foo_bar_baz", state_get_var, - slave_state_get_result, NULL); -} - - -/*** Master state_get() ***/ - - -static void -master_state_get_result (void *cls, int64_t result, - const void *err_msg, uint16_t err_msg_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%d: master_state_get:\t%" PRId64 " (%.*s)\n", - test, result, err_msg_size, (char *) err_msg); - // FIXME: GNUNET_assert (1 == result); - slave_state_get (); -} - - -static void -master_state_get () -{ - test = TEST_MASTER_STATE_GET; - GNUNET_PSYC_channel_state_get (mst_chn, "_foo_bar_baz", state_get_var, - master_state_get_result, NULL); -} - - -/*** Slave history_replay() ***/ - -static void -slave_history_replay_result (void *cls, int64_t result, - const void *err_msg, uint16_t err_msg_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%d: slave_history_replay:\t%" PRId64 " (%.*s)\n", - test, result, - (int) err_msg_size, - (const char *) err_msg); - GNUNET_assert (9 == result); - - master_state_get (); -} - - -static void -slave_history_replay () -{ - test = TEST_SLAVE_HISTORY_REPLAY; - GNUNET_PSYC_channel_history_replay (slv_chn, 1, 1, "", - GNUNET_PSYC_HISTORY_REPLAY_LOCAL, - slave_message_cb, - slave_message_part_cb, - slave_history_replay_result, NULL); -} - - -/*** Master history_replay() ***/ - - -static void -master_history_replay_result (void *cls, int64_t result, - const void *err_msg, uint16_t err_msg_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%d: master_history_replay:\t%" PRId64 " (%.*s)\n", - test, result, - (int) err_msg_size, - (const char *) err_msg); - GNUNET_assert (9 == result); - - slave_history_replay (); -} - - -static void -master_history_replay () -{ - test = TEST_MASTER_HISTORY_REPLAY; - GNUNET_PSYC_channel_history_replay (mst_chn, 1, 1, "", - GNUNET_PSYC_HISTORY_REPLAY_LOCAL, - master_message_cb, - master_message_part_cb, - master_history_replay_result, NULL); -} - - -/*** Slave history_replay_latest() ***/ - - -static void -slave_history_replay_latest_result (void *cls, int64_t result, - const void *err_msg, uint16_t err_msg_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%d: slave_history_replay_latest:\t%" PRId64 " (%.*s)\n", - test, result, - (int) err_msg_size, - (const char *) err_msg); - GNUNET_assert (9 == result); - - master_history_replay (); -} - - -static void -slave_history_replay_latest () -{ - test = TEST_SLAVE_HISTORY_REPLAY_LATEST; - GNUNET_PSYC_channel_history_replay_latest (slv_chn, 1, "", - GNUNET_PSYC_HISTORY_REPLAY_LOCAL, - &slave_message_cb, - &slave_message_part_cb, - &slave_history_replay_latest_result, - NULL); -} - - -/*** Master history_replay_latest() ***/ - - -static void -master_history_replay_latest_result (void *cls, int64_t result, - const void *err_msg, uint16_t err_msg_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%d: master_history_replay_latest:\t%" PRId64 " (%.*s)\n", - test, result, err_msg_size, (char *) err_msg); - GNUNET_assert (9 == result); - - slave_history_replay_latest (); -} - - -static void -master_history_replay_latest () -{ - test = TEST_MASTER_HISTORY_REPLAY_LATEST; - GNUNET_PSYC_channel_history_replay_latest (mst_chn, 1, "", - GNUNET_PSYC_HISTORY_REPLAY_LOCAL, - &master_message_cb, - &master_message_part_cb, - &master_history_replay_latest_result, - NULL); -} - - -static void -transmit_resume (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Test #%d: Transmission resumed.\n", test); - struct TransmitClosure *tmit = cls; - if (NULL != tmit->mst_tmit) - GNUNET_PSYC_master_transmit_resume (tmit->mst_tmit); - else - GNUNET_PSYC_slave_transmit_resume (tmit->slv_tmit); -} - - -static int -tmit_notify_data (void *cls, uint16_t *data_size, void *data) -{ - struct TransmitClosure *tmit = cls; - if (0 == tmit->data_count) - { - *data_size = 0; - return GNUNET_YES; - } - - uint16_t size = strlen (tmit->data[tmit->n]); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Test #%d: Transmit notify data: %u bytes available, " - "processing fragment %u/%u (size %u).\n", - test, *data_size, tmit->n + 1, tmit->data_count, size); - if (*data_size < size) - { - *data_size = 0; - GNUNET_assert (0); - return GNUNET_SYSERR; - } - - if (GNUNET_YES != tmit->paused && 0 < tmit->data_delay[tmit->n]) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Test #%d: Transmission paused.\n", test); - tmit->paused = GNUNET_YES; - GNUNET_SCHEDULER_add_delayed ( - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, - tmit->data_delay[tmit->n]), - &transmit_resume, tmit); - *data_size = 0; - return GNUNET_NO; - } - tmit->paused = GNUNET_NO; - - *data_size = size; - GNUNET_memcpy (data, tmit->data[tmit->n], size); - - return ++tmit->n < tmit->data_count ? GNUNET_NO : GNUNET_YES; -} - - -static int -tmit_notify_mod (void *cls, uint16_t *data_size, void *data, uint8_t *oper, - uint32_t *full_value_size) -{ - struct TransmitClosure *tmit = cls; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Test #%d: Transmit notify modifier: %u bytes available, " - "%u modifiers left to process.\n", - test, *data_size, (unsigned int) GNUNET_PSYC_env_get_count (tmit->env)); - - uint16_t name_size = 0; - size_t value_size = 0; - const char *value = NULL; - - if (NULL != oper && NULL != tmit->mod) - { /* New modifier */ - tmit->mod = tmit->mod->next; - if (NULL == tmit->mod) - { /* No more modifiers, continue with data */ - *data_size = 0; - return GNUNET_YES; - } - - GNUNET_assert (tmit->mod->value_size < UINT32_MAX); - *full_value_size = tmit->mod->value_size; - *oper = tmit->mod->oper; - name_size = strlen (tmit->mod->name); - - if (name_size + 1 + tmit->mod->value_size <= *data_size) - { - *data_size = name_size + 1 + tmit->mod->value_size; - } - else - { - tmit->mod_value_size = tmit->mod->value_size; - value_size = *data_size - name_size - 1; - tmit->mod_value_size -= value_size; - tmit->mod_value = tmit->mod->value + value_size; - } - - GNUNET_memcpy (data, tmit->mod->name, name_size); - ((char *)data)[name_size] = '\0'; - GNUNET_memcpy ((char *)data + name_size + 1, tmit->mod->value, value_size); - } - else if (NULL != tmit->mod_value && 0 < tmit->mod_value_size) - { /* Modifier continuation */ - value = tmit->mod_value; - if (tmit->mod_value_size <= *data_size) - { - value_size = tmit->mod_value_size; - tmit->mod_value = NULL; - } - else - { - value_size = *data_size; - tmit->mod_value += value_size; - } - tmit->mod_value_size -= value_size; - - if (*data_size < value_size) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "value larger than buffer: %u < %zu\n", - *data_size, value_size); - *data_size = 0; - return GNUNET_NO; - } - - *data_size = value_size; - GNUNET_memcpy (data, value, value_size); - } - - return GNUNET_NO; -} - - -static void -slave_join (); - - -static void -slave_transmit () -{ - test = TEST_SLAVE_TRANSMIT; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%d: Slave sending request to master.\n", test); - - tmit = GNUNET_new (struct TransmitClosure); - tmit->env = GNUNET_PSYC_env_create (); - GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN, - "_abc", "abc def", 7); - GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN, - "_abc_def", "abc def ghi", 11); - tmit->mod = GNUNET_PSYC_env_head (tmit->env); - tmit->n = 0; - tmit->data[0] = "slave test"; - tmit->data_count = 1; - tmit->slv_tmit - = GNUNET_PSYC_slave_transmit (slv, "_request_test", &tmit_notify_mod, - &tmit_notify_data, tmit, - GNUNET_PSYC_SLAVE_TRANSMIT_NONE); -} - - -static void -slave_remove_cb (void *cls, int64_t result, - const void *err_msg, uint16_t err_msg_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%d: slave_remove:\t%" PRId64 " (%.*s)\n", - test, result, err_msg_size, (char *) err_msg); - - slave_transmit (); -} - - -static void -slave_remove () -{ - test = TEST_SLAVE_REMOVE; - struct GNUNET_PSYC_Channel *chn = GNUNET_PSYC_master_get_channel (mst); - GNUNET_PSYC_channel_slave_remove (chn, &slave_pub_key, 2, - &slave_remove_cb, chn); -} - - -static void -slave_add_cb (void *cls, int64_t result, - const void *err_msg, uint16_t err_msg_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%d: slave_add:\t%" PRId64 " (%.*s)\n", - test, result, err_msg_size, (char *) err_msg); - slave_remove (); -} - - -static void -slave_add () -{ - test = TEST_SLAVE_ADD; - struct GNUNET_PSYC_Channel *chn = GNUNET_PSYC_master_get_channel (mst); - GNUNET_PSYC_channel_slave_add (chn, &slave_pub_key, 2, 2, &slave_add_cb, chn); -} - - -static void -schedule_second_slave_join (void *cls) -{ - slave_join (TEST_SLAVE_JOIN_ACCEPT); -} - - -static void -first_slave_parted (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "First slave parted.\n"); - GNUNET_SCHEDULER_add_now (&schedule_second_slave_join, NULL); -} - - -static void -schedule_first_slave_part (void *cls) -{ - GNUNET_PSYC_slave_part (slv, GNUNET_NO, &first_slave_parted, NULL); -} - - -static void -join_decision_cb (void *cls, - const struct GNUNET_PSYC_JoinDecisionMessage *dcsn, - int is_admitted, - const struct GNUNET_PSYC_Message *join_msg) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%d: Slave got join decision: %d\n", test, is_admitted); - - switch (test) - { - case TEST_SLAVE_JOIN_REJECT: - GNUNET_assert (0 == is_admitted); - GNUNET_assert (1 == join_req_count); - GNUNET_SCHEDULER_add_now (&schedule_first_slave_part, NULL); - break; - - case TEST_SLAVE_JOIN_ACCEPT: - GNUNET_assert (1 == is_admitted); - GNUNET_assert (2 == join_req_count); - slave_add (); - break; - - default: - GNUNET_break (0); - } -} - - -static void -join_request_cb (void *cls, - const struct GNUNET_PSYC_JoinRequestMessage *req, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - const struct GNUNET_PSYC_Message *join_msg, - struct GNUNET_PSYC_JoinHandle *jh) -{ - struct GNUNET_HashCode slave_key_hash; - GNUNET_CRYPTO_hash (slave_key, sizeof (*slave_key), &slave_key_hash); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%d: Got join request #%u from %s.\n", - test, join_req_count, GNUNET_h2s (&slave_key_hash)); - - /* Reject first request */ - int is_admitted = (0 < join_req_count++) ? GNUNET_YES : GNUNET_NO; - GNUNET_PSYC_join_decision (jh, is_admitted, 0, NULL, NULL); -} - - -static void -slave_connect_cb (void *cls, int result, uint64_t max_message_id) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%d: Slave connected: %d, max_message_id: %" PRIu64 "\n", - test, result, max_message_id); - GNUNET_assert (TEST_SLAVE_JOIN_REJECT == test || TEST_SLAVE_JOIN_ACCEPT == test); - GNUNET_assert (GNUNET_OK == result || GNUNET_NO == result); -} - - -static void -slave_join (int t) -{ - test = t; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%d: Joining slave.\n", t); - - struct GNUNET_PeerIdentity origin = this_peer; - struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); - GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN, - "_foo", "bar baz", 7); - GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN, - "_foo_bar", "foo bar baz", 11); - struct GNUNET_PSYC_Message * - join_msg = GNUNET_PSYC_message_create ("_request_join", env, "some data", 9); - - slv = GNUNET_PSYC_slave_join (cfg, - &channel_pub_key, - slave_key, - GNUNET_PSYC_SLAVE_JOIN_NONE, - &origin, - 0, - NULL, - &slave_message_cb, - &slave_message_part_cb, - &slave_connect_cb, - &join_decision_cb, - NULL, - join_msg); - GNUNET_free (join_msg); - slv_chn = GNUNET_PSYC_slave_get_channel (slv); - GNUNET_PSYC_env_destroy (env); -} - - -static void -master_transmit () -{ - test = TEST_MASTER_TRANSMIT; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%d: Master sending message to all.\n", test); - end_count = 0; - - uint32_t i, j; - - char *name_max = "_test_max"; - uint8_t name_max_size = sizeof ("_test_max"); - char *val_max = GNUNET_malloc (GNUNET_PSYC_MODIFIER_MAX_PAYLOAD); - for (i = 0; i < GNUNET_PSYC_MODIFIER_MAX_PAYLOAD; i++) - val_max[i] = (0 == i % 10000) ? '0' + i / 10000 : '.'; - - char *name_cont = "_test_cont"; - uint8_t name_cont_size = sizeof ("_test_cont"); - char *val_cont = GNUNET_malloc (GNUNET_PSYC_MODIFIER_MAX_PAYLOAD - + GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD); - for (i = 0; i < GNUNET_PSYC_MODIFIER_MAX_PAYLOAD - name_cont_size; i++) - val_cont[i] = (0 == i % 10000) ? '0' + i / 10000 : ':'; - for (j = 0; j < GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD; j++, i++) - val_cont[i] = (0 == j % 10000) ? '0' + j / 10000 : '!'; - - tmit = GNUNET_new (struct TransmitClosure); - tmit->env = GNUNET_PSYC_env_create (); - GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN, - "_foo", "bar baz", 7); - GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN, - name_max, val_max, - GNUNET_PSYC_MODIFIER_MAX_PAYLOAD - - name_max_size); - GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN, - "_foo_bar", "foo bar baz", 11); - GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN, - name_cont, val_cont, - GNUNET_PSYC_MODIFIER_MAX_PAYLOAD - name_cont_size - + GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD); - tmit->mod = GNUNET_PSYC_env_head (tmit->env); - tmit->data[0] = "foo"; - tmit->data[1] = GNUNET_malloc (GNUNET_PSYC_DATA_MAX_PAYLOAD + 1); - for (i = 0; i < GNUNET_PSYC_DATA_MAX_PAYLOAD; i++) - tmit->data[1][i] = (0 == i % 10000) ? '0' + i / 10000 : '_'; - tmit->data[2] = "foo bar"; - tmit->data[3] = "foo bar baz"; - tmit->data_delay[1] = 3; - tmit->data_count = 4; - tmit->mst_tmit - = GNUNET_PSYC_master_transmit (mst, "_notice_test", &tmit_notify_mod, - &tmit_notify_data, tmit, - GNUNET_PSYC_MASTER_TRANSMIT_INC_GROUP_GEN); -} - - -static void -master_start_cb (void *cls, int result, uint64_t max_message_id) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Test #%d: Master started: %d, max_message_id: %" PRIu64 "\n", - test, result, max_message_id); - GNUNET_assert (TEST_MASTER_START == test); - GNUNET_assert (GNUNET_OK == result || GNUNET_NO == result); - slave_join (TEST_SLAVE_JOIN_REJECT); -} - - -static void -master_start () -{ - test = TEST_MASTER_START; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Test #%d: Starting master.\n", test); - mst = GNUNET_PSYC_master_start (cfg, channel_key, GNUNET_PSYC_CHANNEL_PRIVATE, - &master_start_cb, &join_request_cb, - &master_message_cb, &master_message_part_cb, - NULL); - mst_chn = GNUNET_PSYC_master_get_channel (mst); -} - - -static void -schedule_master_start (void *cls) -{ - master_start (); -} - - -/** - * Main function of the test, run from scheduler. - * - * @param cls NULL - * @param cfg configuration we use (also to connect to PSYC service) - * @param peer handle to access more of the peer (not used) - */ -static void -#if DEBUG_TEST_PSYC -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *c) -#else -run (void *cls, - const struct GNUNET_CONFIGURATION_Handle *c, - struct GNUNET_TESTING_Peer *peer) -#endif -{ - cfg = c; - end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); - - GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer); - - channel_key = GNUNET_CRYPTO_eddsa_key_create (); - slave_key = GNUNET_CRYPTO_ecdsa_key_create (); - - GNUNET_CRYPTO_eddsa_key_get_public (channel_key, &channel_pub_key); - GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key); - -#if DEBUG_TEST_PSYC - master_start (); -#else - /* Allow some time for the services to initialize. */ - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, - &schedule_master_start, NULL); -#endif -} - - -int -main (int argc, char *argv[]) -{ - res = 1; -#if DEBUG_TEST_PSYC - const struct GNUNET_GETOPT_CommandLineOption opts[] = { - GNUNET_GETOPT_OPTION_END - }; - if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-psyc", - "test-psyc [options]", - opts, &run, NULL)) - return 1; -#else - if (0 != GNUNET_TESTING_peer_run ("test-psyc", "test_psyc.conf", &run, NULL)) - return 1; -#endif - return res; -} - -/* end of test_psyc.c */ diff --git a/src/psyc/test_psyc.conf b/src/psyc/test_psyc.conf deleted file mode 100644 index 6ff031f0d..000000000 --- a/src/psyc/test_psyc.conf +++ /dev/null @@ -1,28 +0,0 @@ -@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf - -[testbed] -HOSTNAME = localhost -OVERLAY_TOPOLOGY = STAR - -[peerinfo] -# Option to disable all disk IO; only useful for testbed runs -# (large-scale experiments); disables persistence of HELLOs! -NO_IO = YES - -[cadet] -ID_ANNOUNCE_TIME = 5 s - -[nat] -ENABLE_UPNP = NO - -[psyc] -IMMEDIATE_START = YES -START_ON_DEMAND = YES - -[multicast] -IMMEDIATE_START = YES -START_ON_DEMAND = YES - -[psycstore] -IMMEDIATE_START = YES -START_ON_DEMAND = YES diff --git a/src/psyc/test_psyc2.c b/src/psyc/test_psyc2.c deleted file mode 100644 index c6e7237ab..000000000 --- a/src/psyc/test_psyc2.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file psyc/test_psyc2.c - * @brief Testbed test for the PSYC API. - * @author xrs - */ - -#include "platform.h" -#include "gnunet_crypto_lib.h" -#include "gnunet_common.h" -#include "gnunet_util_lib.h" -#include "gnunet_testbed_service.h" -#include "gnunet_psyc_util_lib.h" -#include "gnunet_psyc_service.h" - -#define PEERS_REQUESTED 2 - -static int result; - -static struct GNUNET_SCHEDULER_Task *timeout_tid; -static struct pctx **pctx; - -static struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key; -static struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key; - -static struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key; -static struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; - -/** - * Task To perform tests - */ -static struct GNUNET_SCHEDULER_Task *test_task; - -/** - * Peer id couter - */ -static unsigned int pids; - -struct pctx -{ - int idx; - struct GNUNET_TESTBED_Peer *peer; - const struct GNUNET_PeerIdentity *id; - - struct GNUNET_TESTBED_Operation *op; - - /** - * psyc service handle - */ - void *psyc; - struct GNUNET_PSYC_Master *mst; - struct GNUNET_PSYC_Slave *slv; - - /** - * result for test on peer - */ - int test_ok; -}; - -static void -shutdown_task (void *cls) -{ - if (NULL != pctx) - { - if (NULL != pctx[0]->mst) - GNUNET_PSYC_master_stop (pctx[0]->mst, GNUNET_NO, NULL, NULL); - - for (int i=0; i < PEERS_REQUESTED; i++) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Operation done.\n"); - GNUNET_TESTBED_operation_done (pctx[i]->op); - GNUNET_free_non_null (pctx[i]); - } - GNUNET_free (pctx); - } - - if (NULL != timeout_tid) - GNUNET_SCHEDULER_cancel (timeout_tid); -} - -static void -timeout_task (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout!\n"); - result = GNUNET_SYSERR; - GNUNET_SCHEDULER_shutdown (); -} - -static void -start_test (void *cls) -{ -} - -static void -pinfo_cb (void *cls, - struct GNUNET_TESTBED_Operation *operation, - const struct GNUNET_TESTBED_PeerInformation *pinfo, - const char *emsg) -{ - struct pctx *pc = (struct pctx*) cls; - - pc->id = pinfo->result.id; - - pids++; - if (pids < (PEERS_REQUESTED - 1)) - return; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got all IDs, starting test\n"); - test_task = GNUNET_SCHEDULER_add_now (&start_test, NULL); -} - -static void -mst_start_cb () -{ -} - -static void -join_request_cb () -{ -} - -static void -mst_message_cb () -{ -} - -static void -mst_message_part_cb () -{ -} - -static void -slv_message_cb () -{ -} - -static void -slv_message_part_cb () -{ -} - -static void -slv_connect_cb () -{ -} - -static void -join_decision_cb () -{ -} - -static void * -psyc_ca (void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct GNUNET_PSYC_Message *join_msg = NULL; - struct pctx *pc = (struct pctx *) cls; - - if (0 == pc->idx) - { - pc->mst = GNUNET_PSYC_master_start (cfg, channel_key, - GNUNET_PSYC_CHANNEL_PRIVATE, - &mst_start_cb, &join_request_cb, - &mst_message_cb, &mst_message_part_cb, - NULL); - return pc->mst; - } - - pc->slv = GNUNET_PSYC_slave_join (cfg, &channel_pub_key, slave_key, - GNUNET_PSYC_SLAVE_JOIN_NONE, - &pid, 0, NULL, &slv_message_cb, - &slv_message_part_cb, - &slv_connect_cb, &join_decision_cb, - NULL, join_msg); - return pc->slv; -} - -static void -psyc_da (void *cls, - void *op_result) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Disconnected from service.\n"); -} - -static void -service_connect (void *cls, - struct GNUNET_TESTBED_Operation *op, - void *ca_result, - const char *emsg) -{ - struct pctx *pc = (struct pctx *) cls; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Connected to service\n"); - - GNUNET_assert (NULL != ca_result); - - // FIXME: we need a simple service handle to connect to the service, then - // get peer information and AFTER that make PSYC ops. Compare to CADET. - pc->psyc = ca_result; - - GNUNET_TESTBED_peer_get_information (pc->peer, - GNUNET_TESTBED_PIT_IDENTITY, - pinfo_cb, pc); -} - -static void -testbed_master (void *cls, - struct GNUNET_TESTBED_RunHandle *h, - unsigned int num_peers, - struct GNUNET_TESTBED_Peer **p, - unsigned int links_succeeded, - unsigned int links_failed) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to testbed_master()\n"); - - // Create ctx for peers - pctx = GNUNET_new_array (PEERS_REQUESTED, struct pctx*); - for (int i = 0; iidx = i; - pctx[i]->peer = p[i]; - pctx[i]->id = NULL; - pctx[i]->mst = NULL; - pctx[i]->op = NULL; - pctx[i]->test_ok = GNUNET_NO; - } - - channel_key = GNUNET_CRYPTO_eddsa_key_create (); - slave_key = GNUNET_CRYPTO_ecdsa_key_create (); - - GNUNET_CRYPTO_eddsa_key_get_public (channel_key, &channel_pub_key); - GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key); - - pctx[0]->op = - GNUNET_TESTBED_service_connect (NULL, p[0], "psyc", service_connect, - pctx[0], psyc_ca, psyc_da, pctx[0]); - - GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); - - timeout_tid = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5), - &timeout_task, NULL); -} - -int -main (int argc, char *argv[]) -{ - int ret; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "test\n"); - - result = GNUNET_SYSERR; - - ret = GNUNET_TESTBED_test_run ("test-psyc2", "test_psyc.conf", - PEERS_REQUESTED, 0LL, NULL, NULL, - testbed_master, NULL); - - if ((GNUNET_OK != ret) || (GNUNET_OK != result)) - return 1; - - return 0; -} - -/* end of test-psyc2.c */ diff --git a/src/psyc/test_psyc_api_join.c b/src/psyc/test_psyc_api_join.c deleted file mode 100644 index 419fa11c1..000000000 --- a/src/psyc/test_psyc_api_join.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file psyc/test_psyc_api_join.c - * @brief Testbed test for the PSYC API. - * @author xrs - */ - -/** - * Lessons Learned: - * - define topology in config - * - psyc slave join needs part to end (same with master) - * - GNUNET_SCHEDULER_add_delayed return value will outdate at call time - * - main can not contain GNUNET_log() - */ - -#include "platform.h" -#include "gnunet_crypto_lib.h" -#include "gnunet_common.h" -#include "gnunet_util_lib.h" -#include "gnunet_testbed_service.h" -#include "gnunet_psyc_util_lib.h" -#include "gnunet_psyc_service.h" -#include "psyc_test_lib.h" - -static struct pctx PEERS[2]; - -static int pids; - - -static void -shutdown_task (void *cls) -{ - if (NULL != timeout_task_id) { - GNUNET_SCHEDULER_cancel (timeout_task_id); - timeout_task_id = NULL; - } - - for (int i=0;i<2;i++) { - GNUNET_free (PEERS[i].channel_pub_key); - - if (NULL != PEERS[i].psyc) - { - if (0 == i) - GNUNET_PSYC_master_stop (PEERS[i].psyc, GNUNET_NO, NULL, NULL); - else - GNUNET_PSYC_slave_part (PEERS[i].psyc, GNUNET_NO, NULL, NULL); - } - } - - for (int i=0;iidx) { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting to PSYC as master ...\n"); - - peer->psyc = (struct GNUNET_PSYC_Master *) - GNUNET_PSYC_master_start (cfg, - peer->channel_key, - GNUNET_PSYC_CHANNEL_PRIVATE, - NULL, - join_request_cb, - NULL, - NULL, - cls); - return peer->psyc; - } - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting to PSYC as slave ...\n"); - - struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); - GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN, "_foo", "bar baz", 7); - GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN, "_foo_bar", "foo bar baz", 11); - - struct GNUNET_PSYC_Message * - join_msg = GNUNET_PSYC_message_create ("_request_join", env, "some data", 40); - - peer->psyc = (struct GNUNET_PSYC_Slave *) - GNUNET_PSYC_slave_join (cfg, - peer->channel_pub_key, - peer->id_key, - GNUNET_PSYC_SLAVE_JOIN_NONE, - peer->peer_id_master, - 0, - NULL, - NULL, - NULL, - NULL, - join_decision_cb, - cls, - join_msg); - - GNUNET_free (join_msg); - peer->channel = GNUNET_PSYC_slave_get_channel (peer->psyc); - GNUNET_PSYC_env_destroy (env); - - return peer->psyc; -} - -static void -service_connect (void *cls, - struct GNUNET_TESTBED_Operation *op, - void *ca_result, - const char *emsg) -{ - GNUNET_assert (NULL != ca_result); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to the service\n"); -} - -static void -connect_to_services (void *cls) -{ - for (int i = 0; i < 2; i++) - { - PEERS[i].peer_id_master = PEERS[0].peer_id; - - op[op_cnt++] = - GNUNET_TESTBED_service_connect (NULL, PEERS[i].testbed_peer, "psyc", - &service_connect, &PEERS[i], &psyc_ca, - &psyc_da, &PEERS[i]); - } -} - -static void -pinfo_cb (void *cls, - struct GNUNET_TESTBED_Operation *operation, - const struct GNUNET_TESTBED_PeerInformation *pinfo, - const char *emsg) -{ - struct pctx *peer = (struct pctx*) cls; - - peer->peer_id = pinfo->result.id; - - pids++; - if (pids < 2) - return; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got all IDs, starting test\n"); - - GNUNET_SCHEDULER_add_now (&connect_to_services, NULL); -} - -static void -testbed_master (void *cls, - struct GNUNET_TESTBED_RunHandle *h, - unsigned int num_peers, - struct GNUNET_TESTBED_Peer **p, - unsigned int links_succeeded, - unsigned int links_failed) -{ - struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key = NULL; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to testbed_master\n"); - - // Set up shutdown logic - GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); - timeout_task_id = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 15), - &timeout_task, NULL); - GNUNET_assert (NULL != timeout_task_id); - - // Set up channel key - channel_key = GNUNET_CRYPTO_eddsa_key_create (); - GNUNET_assert (NULL != channel_key); - - // Set up information contexts for peers - for (int i=0 ; i < 2 ; i++) - { - PEERS[i].idx = i; - PEERS[i].testbed_peer = p[i]; - - // Create "egos" - PEERS[i].id_key = GNUNET_CRYPTO_ecdsa_key_create (); - - // Set up channel keys shared by master and slave - PEERS[i].channel_key = channel_key; - - PEERS[i].channel_pub_key = - GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); - // Get public key - GNUNET_CRYPTO_eddsa_key_get_public (PEERS[i].channel_key, - PEERS[i].channel_pub_key); - // Get peerinfo - op[op_cnt++] = - GNUNET_TESTBED_peer_get_information (p[i], - GNUNET_TESTBED_PIT_IDENTITY, - pinfo_cb, &PEERS[i]); - } -} - -int -main (int argc, char *argv[]) -{ - int ret; - - ret = GNUNET_TESTBED_test_run ("test_psyc_api_join", "test_psyc.conf", - 2, 0LL, NULL, NULL, - &testbed_master, NULL); - - if ( (GNUNET_OK != ret) || (GNUNET_OK != result) ) - return 1; - - return 0; -} - -/* end of test_psyc_api_join.c */ diff --git a/src/psycstore/.gitignore b/src/psycstore/.gitignore deleted file mode 100644 index 5ec783202..000000000 --- a/src/psycstore/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -gnunet-service-psycstore -test_plugin_psycstore_mysql -test_plugin_psycstore_sqlite -test_plugin_psycstore_postgres -test_psycstore diff --git a/src/psycstore/Makefile.am b/src/psycstore/Makefile.am deleted file mode 100644 index 557bb42b5..000000000 --- a/src/psycstore/Makefile.am +++ /dev/null @@ -1,155 +0,0 @@ -# This Makefile.am is in the public domain -AM_CPPFLAGS = -I$(top_srcdir)/src/include - -plugindir = $(libdir)/gnunet - -pkgcfgdir= $(pkgdatadir)/config.d/ - -libexecdir= $(pkglibdir)/libexec/ - -pkgcfg_DATA = \ - psycstore.conf - - -if MINGW - WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -endif - -if USE_COVERAGE - AM_CFLAGS = --coverage -O0 - XLIB = -lgcov -endif - -if HAVE_MYSQL -MYSQL_PLUGIN = libgnunet_plugin_psycstore_mysql.la -if HAVE_TESTING -MYSQL_TESTS = test_plugin_psycstore_mysql -endif -endif - -if HAVE_POSTGRESQL -POSTGRES_PLUGIN = libgnunet_plugin_psycstore_postgres.la -if HAVE_TESTING -POSTGRES_TESTS = test_plugin_psycstore_postgres -endif -endif - -if HAVE_SQLITE -SQLITE_PLUGIN = libgnunet_plugin_psycstore_sqlite.la -if HAVE_TESTING -SQLITE_TESTS = test_plugin_psycstore_sqlite -endif -endif - -lib_LTLIBRARIES = libgnunetpsycstore.la - -libgnunetpsycstore_la_SOURCES = \ - psycstore_api.c \ - psycstore.h -libgnunetpsycstore_la_LIBADD = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(GN_LIBINTL) $(XLIB) -libgnunetpsycstore_la_LDFLAGS = \ - $(GN_LIB_LDFLAGS) $(WINFLAGS) \ - -version-info 0:0:0 - -bin_PROGRAMS = - -libexec_PROGRAMS = \ - gnunet-service-psycstore - -gnunet_service_psycstore_SOURCES = \ - gnunet-service-psycstore.c -gnunet_service_psycstore_LDADD = \ - $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/psycutil/libgnunetpsycutil.la \ - $(GN_LIBINTL) - -plugin_LTLIBRARIES = \ - $(SQLITE_PLUGIN) \ - $(MYSQL_PLUGIN) \ - $(POSTGRES_PLUGIN) - - -libgnunet_plugin_psycstore_mysql_la_SOURCES = \ - plugin_psycstore_mysql.c -libgnunet_plugin_psycstore_mysql_la_LIBADD = \ - libgnunetpsycstore.la \ - $(top_builddir)/src/my/libgnunetmy.la \ - $(top_builddir)/src/mysql/libgnunetmysql.la \ - $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ - $(LTLIBINTL) -libgnunet_plugin_psycstore_mysql_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) - -libgnunet_plugin_psycstore_postgres_la_SOURCES = \ - plugin_psycstore_postgres.c -libgnunet_plugin_psycstore_postgres_la_LIBADD = \ - libgnunetpsycstore.la \ - $(top_builddir)/src/pq/libgnunetpq.la \ - $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq \ - $(LTLIBINTL) -libgnunet_plugin_psycstore_postgres_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) $(POSTGRESQL_LDFLAGS) -libgnunet_plugin_psycstore_postgres_la_CPPFLAGS = \ - $(POSTGRESQL_CPPFLAGS) $(AM_CPPFLAGS) - - -libgnunet_plugin_psycstore_sqlite_la_SOURCES = \ - plugin_psycstore_sqlite.c -libgnunet_plugin_psycstore_sqlite_la_LIBADD = \ - libgnunetpsycstore.la \ - $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \ - $(LTLIBINTL) -libgnunet_plugin_psycstore_sqlite_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) - - -if HAVE_SQLITE -if HAVE_TESTING -check_PROGRAMS = \ - $(SQLITE_TESTS) \ - $(MYSQL_TESTS) \ - $(POSTGRES_TESTS) \ - test_psycstore -endif -endif - -if ENABLE_TEST_RUN -AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; -TESTS = $(check_PROGRAMS) -endif - -test_psycstore_SOURCES = \ - test_psycstore.c -test_psycstore_LDADD = \ - libgnunetpsycstore.la \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/util/libgnunetutil.la - -EXTRA_DIST = \ - test_psycstore.conf - - -test_plugin_psycstore_sqlite_SOURCES = \ - test_plugin_psycstore.c -test_plugin_psycstore_sqlite_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_plugin_psycstore_mysql_SOURCES = \ - test_plugin_psycstore.c -test_plugin_psycstore_mysql_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_plugin_psycstore_postgres_SOURCES = \ - test_plugin_psycstore.c -test_plugin_psycstore_postgres_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/util/libgnunetutil.la - diff --git a/src/psycstore/gnunet-service-psycstore.c b/src/psycstore/gnunet-service-psycstore.c deleted file mode 100644 index 9aebd3e97..000000000 --- a/src/psycstore/gnunet-service-psycstore.c +++ /dev/null @@ -1,1049 +0,0 @@ -/** - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file psycstore/gnunet-service-psycstore.c - * @brief PSYCstore service - * @author Gabor X Toth - * @author Christian Grothoff - */ - -#include - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_constants.h" -#include "gnunet_protocols.h" -#include "gnunet_statistics_service.h" -#include "gnunet_psyc_util_lib.h" -#include "gnunet_psycstore_service.h" -#include "gnunet_psycstore_plugin.h" -#include "psycstore.h" - - -/** - * Handle to our current configuration. - */ -static const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * Service handle. - */ -static struct GNUNET_SERVICE_Handle *service; - -/** - * Handle to the statistics service. - */ -static struct GNUNET_STATISTICS_Handle *stats; - -/** - * Database handle - */ -static struct GNUNET_PSYCSTORE_PluginFunctions *db; - -/** - * Name of the database plugin - */ -static char *db_lib_name; - - -/** - * Task run during shutdown. - * - * @param cls unused - */ -static void -shutdown_task (void *cls) -{ - if (NULL != stats) - { - GNUNET_STATISTICS_destroy (stats, GNUNET_NO); - stats = NULL; - } - GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, db)); - GNUNET_free (db_lib_name); - db_lib_name = NULL; -} - - -/** - * Send a result code back to the client. - * - * @param client - * Client that should receive the result code. - * @param result_code - * Code to transmit. - * @param op_id - * Operation ID in network byte order. - * @param err_msg - * Error message to include (or NULL for none). - */ -static void -send_result_code (struct GNUNET_SERVICE_Client *client, - uint64_t op_id, - int64_t result_code, - const char *err_msg) -{ - struct OperationResult *res; - size_t err_size = 0; - - if (NULL != err_msg) - err_size = strnlen (err_msg, - GNUNET_MAX_MESSAGE_SIZE - sizeof (*res) - 1) + 1; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (res, err_size, - GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE); - res->result_code = GNUNET_htonll (result_code - INT64_MIN); - res->op_id = op_id; - if (0 < err_size) - { - GNUNET_memcpy (&res[1], err_msg, err_size); - ((char *) &res[1])[err_size - 1] = '\0'; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending result to client: %" PRId64 " (%s)\n", - result_code, err_msg); - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env); -} - - -enum -{ - MEMBERSHIP_TEST_NOT_NEEDED = 0, - MEMBERSHIP_TEST_NEEDED = 1, - MEMBERSHIP_TEST_DONE = 2, -} MessageMembershipTest; - - -struct SendClosure -{ - struct GNUNET_SERVICE_Client *client; - - /** - * Channel's public key. - */ - struct GNUNET_CRYPTO_EddsaPublicKey channel_key; - - /** - * Slave's public key. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey slave_key; - - /** - * Operation ID. - */ - uint64_t op_id; - - /** - * Membership test result. - */ - int membership_test_result; - - /** - * Do membership test with @a slave_key before returning fragment? - * @see enum MessageMembershipTest - */ - uint8_t membership_test; -}; - - -static int -send_fragment (void *cls, struct GNUNET_MULTICAST_MessageHeader *msg, - enum GNUNET_PSYCSTORE_MessageFlags flags) -{ - struct SendClosure *sc = cls; - struct FragmentResult *res; - - if (MEMBERSHIP_TEST_NEEDED == sc->membership_test) - { - sc->membership_test = MEMBERSHIP_TEST_DONE; - sc->membership_test_result - = db->membership_test (db->cls, &sc->channel_key, &sc->slave_key, - GNUNET_ntohll (msg->message_id)); - switch (sc->membership_test_result) - { - case GNUNET_YES: - break; - - case GNUNET_NO: - case GNUNET_SYSERR: - return GNUNET_NO; - } - } - - size_t msg_size = ntohs (msg->header.size); - - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (res, msg_size, - GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_FRAGMENT); - res->op_id = sc->op_id; - res->psycstore_flags = htonl (flags); - GNUNET_memcpy (&res[1], msg, msg_size); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending fragment %llu to client\n", - (unsigned long long) GNUNET_ntohll (msg->fragment_id)); - GNUNET_free (msg); - - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (sc->client), env); - return GNUNET_YES; -} - - -static int -send_state_var (void *cls, const char *name, - const void *value, uint32_t value_size) -{ - struct SendClosure *sc = cls; - struct StateResult *res; - size_t name_size = strlen (name) + 1; - - /** @todo FIXME: split up value into 64k chunks */ - - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (res, name_size + value_size, - GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_STATE); - res->op_id = sc->op_id; - res->name_size = htons (name_size); - GNUNET_memcpy (&res[1], name, name_size); - GNUNET_memcpy ((char *) &res[1] + name_size, value, value_size); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending state variable %s to client\n", name); - - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (sc->client), env); - return GNUNET_OK; -} - - -static void -handle_client_membership_store (void *cls, - const struct MembershipStoreRequest *req) -{ - struct GNUNET_SERVICE_Client *client = cls; - - int ret = db->membership_store (db->cls, &req->channel_key, &req->slave_key, - req->did_join, - GNUNET_ntohll (req->announced_at), - GNUNET_ntohll (req->effective_since), - GNUNET_ntohll (req->group_generation)); - - if (ret != GNUNET_OK) - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Failed to store membership information!\n")); - - send_result_code (client, req->op_id, ret, NULL); - GNUNET_SERVICE_client_continue (client); -} - - -static void -handle_client_membership_test (void *cls, - const struct MembershipTestRequest *req) -{ - struct GNUNET_SERVICE_Client *client = cls; - - int ret = db->membership_test (db->cls, &req->channel_key, &req->slave_key, - GNUNET_ntohll (req->message_id)); - switch (ret) - { - case GNUNET_YES: - case GNUNET_NO: - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Failed to test membership!\n")); - } - - send_result_code (client, req->op_id, ret, NULL); - GNUNET_SERVICE_client_continue (client); -} - - -static int -check_client_fragment_store (void *cls, - const struct FragmentStoreRequest *req) -{ - return GNUNET_OK; -} - - -static void -handle_client_fragment_store (void *cls, - const struct FragmentStoreRequest *req) -{ - struct GNUNET_SERVICE_Client *client = cls; - - const struct GNUNET_MessageHeader * - msg = GNUNET_MQ_extract_nested_mh (req); - if (NULL == msg - || ntohs (msg->size) < sizeof (struct GNUNET_MULTICAST_MessageHeader)) - { - GNUNET_break (0); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Dropping invalid fragment\n")); - GNUNET_SERVICE_client_drop (client); - return; - } - - int ret = db->fragment_store (db->cls, &req->channel_key, - (const struct GNUNET_MULTICAST_MessageHeader *) - msg, ntohl (req->psycstore_flags)); - - if (ret != GNUNET_OK) - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Failed to store fragment\n")); - - send_result_code (client, req->op_id, ret, NULL); - GNUNET_SERVICE_client_continue (client); -} - - -static void -handle_client_fragment_get (void *cls, - const struct FragmentGetRequest *req) -{ - struct GNUNET_SERVICE_Client *client = cls; - - struct SendClosure - sc = { .op_id = req->op_id, - .client = client, - .channel_key = req->channel_key, - .slave_key = req->slave_key, - .membership_test = req->do_membership_test }; - - int64_t ret; - uint64_t ret_frags = 0; - uint64_t first_fragment_id = GNUNET_ntohll (req->first_fragment_id); - uint64_t last_fragment_id = GNUNET_ntohll (req->last_fragment_id); - uint64_t limit = GNUNET_ntohll (req->fragment_limit); - - if (0 == limit) - ret = db->fragment_get (db->cls, &req->channel_key, - first_fragment_id, last_fragment_id, - &ret_frags, send_fragment, &sc); - else - ret = db->fragment_get_latest (db->cls, &req->channel_key, limit, - &ret_frags, send_fragment, &sc); - - switch (ret) - { - case GNUNET_YES: - case GNUNET_NO: - if (MEMBERSHIP_TEST_DONE == sc.membership_test) - { - switch (sc.membership_test_result) - { - case GNUNET_YES: - break; - - case GNUNET_NO: - ret = GNUNET_PSYCSTORE_MEMBERSHIP_TEST_FAILED; - break; - - case GNUNET_SYSERR: - ret = GNUNET_SYSERR; - break; - } - } - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Failed to get fragment!\n")); - } - send_result_code (client, req->op_id, (ret < 0) ? ret : ret_frags, NULL); - GNUNET_SERVICE_client_continue (client); -} - - -static int -check_client_message_get (void *cls, - const struct MessageGetRequest *req) -{ - return GNUNET_OK; -} - - -static void -handle_client_message_get (void *cls, - const struct MessageGetRequest *req) -{ - struct GNUNET_SERVICE_Client *client = cls; - - uint16_t size = ntohs (req->header.size); - const char *method_prefix = (const char *) &req[1]; - - if (size < sizeof (*req) + 1 - || '\0' != method_prefix[size - sizeof (*req) - 1]) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Message get: invalid method prefix. size: %u < %u?\n", - size, - (unsigned int) (sizeof (*req) + 1)); - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - - struct SendClosure - sc = { .op_id = req->op_id, - .client = client, - .channel_key = req->channel_key, - .slave_key = req->slave_key, - .membership_test = req->do_membership_test }; - - int64_t ret; - uint64_t ret_frags = 0; - uint64_t first_message_id = GNUNET_ntohll (req->first_message_id); - uint64_t last_message_id = GNUNET_ntohll (req->last_message_id); - uint64_t msg_limit = GNUNET_ntohll (req->message_limit); - uint64_t frag_limit = GNUNET_ntohll (req->fragment_limit); - - /** @todo method_prefix */ - if (0 == msg_limit) - ret = db->message_get (db->cls, &req->channel_key, - first_message_id, last_message_id, frag_limit, - &ret_frags, send_fragment, &sc); - else - ret = db->message_get_latest (db->cls, &req->channel_key, msg_limit, - &ret_frags, send_fragment, &sc); - - switch (ret) - { - case GNUNET_YES: - case GNUNET_NO: - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Failed to get message!\n")); - } - - send_result_code (client, req->op_id, (ret < 0) ? ret : ret_frags, NULL); - GNUNET_SERVICE_client_continue (client); -} - - -static void -handle_client_message_get_fragment (void *cls, - const struct MessageGetFragmentRequest *req) -{ - struct GNUNET_SERVICE_Client *client = cls; - - struct SendClosure - sc = { .op_id = req->op_id, .client = client, - .channel_key = req->channel_key, .slave_key = req->slave_key, - .membership_test = req->do_membership_test }; - - int ret = db->message_get_fragment (db->cls, &req->channel_key, - GNUNET_ntohll (req->message_id), - GNUNET_ntohll (req->fragment_offset), - &send_fragment, &sc); - switch (ret) - { - case GNUNET_YES: - case GNUNET_NO: - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Failed to get message fragment!\n")); - } - - send_result_code (client, req->op_id, ret, NULL); - GNUNET_SERVICE_client_continue (client); -} - - -static void -handle_client_counters_get (void *cls, - const struct OperationRequest *req) -{ - struct GNUNET_SERVICE_Client *client = cls; - - struct CountersResult *res; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg (res, GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_COUNTERS); - - int ret = db->counters_message_get (db->cls, &req->channel_key, - &res->max_fragment_id, &res->max_message_id, - &res->max_group_generation); - switch (ret) - { - case GNUNET_OK: - ret = db->counters_state_get (db->cls, &req->channel_key, - &res->max_state_message_id); - case GNUNET_NO: - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Failed to get master counters!\n")); - } - - res->result_code = htonl (ret); - res->op_id = req->op_id; - res->max_fragment_id = GNUNET_htonll (res->max_fragment_id); - res->max_message_id = GNUNET_htonll (res->max_message_id); - res->max_group_generation = GNUNET_htonll (res->max_group_generation); - res->max_state_message_id = GNUNET_htonll (res->max_state_message_id); - - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env); - GNUNET_SERVICE_client_continue (client); -} - - -struct StateModifyClosure -{ - const struct GNUNET_CRYPTO_EddsaPublicKey channel_key; - struct GNUNET_PSYC_ReceiveHandle *recv; - enum GNUNET_PSYC_MessageState msg_state; - char mod_oper; - char *mod_name; - char *mod_value; - uint32_t mod_value_size; - uint32_t mod_value_remaining; -}; - - -static void -recv_state_message_part (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg) -{ - struct StateModifyClosure *scls = cls; - uint16_t psize; - - if (NULL == msg) - { // FIXME: error on unknown message - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "recv_state_message_part() message_id: %" PRIu64 - ", fragment_offset: %" PRIu64 ", flags: %u\n", - GNUNET_ntohll (msg->message_id), - GNUNET_ntohll (msg->fragment_offset), - ntohl (msg->flags)); - - if (NULL == pmsg) - { - scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_ERROR; - return; - } - - switch (ntohs (pmsg->type)) - { - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD: - { - scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_METHOD; - break; - } - - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: - { - struct GNUNET_PSYC_MessageModifier * - pmod = (struct GNUNET_PSYC_MessageModifier *) pmsg; - psize = ntohs (pmod->header.size); - uint16_t name_size = ntohs (pmod->name_size); - uint32_t value_size = ntohl (pmod->value_size); - - const char *name = (const char *) &pmod[1]; - const void *value = name + name_size; - - if (GNUNET_PSYC_OP_SET != pmod->oper) - { // Apply non-transient operation. - if (psize == sizeof (*pmod) + name_size + value_size) - { - db->state_modify_op (db->cls, &scls->channel_key, - pmod->oper, name, value, value_size); - } - else - { - scls->mod_oper = pmod->oper; - scls->mod_name = GNUNET_malloc (name_size); - GNUNET_memcpy (scls->mod_name, name, name_size); - - scls->mod_value_size = value_size; - scls->mod_value = GNUNET_malloc (scls->mod_value_size); - scls->mod_value_remaining - = scls->mod_value_size - (psize - sizeof (*pmod) - name_size); - GNUNET_memcpy (scls->mod_value, value, value_size - scls->mod_value_remaining); - } - } - scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_MODIFIER; - break; - } - - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: - if (GNUNET_PSYC_OP_SET != scls->mod_oper) - { - if (scls->mod_value_remaining == 0) - { - GNUNET_break_op (0); - scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_ERROR; - } - psize = ntohs (pmsg->size); - GNUNET_memcpy (scls->mod_value + (scls->mod_value_size - scls->mod_value_remaining), - &pmsg[1], psize - sizeof (*pmsg)); - scls->mod_value_remaining -= psize - sizeof (*pmsg); - if (0 == scls->mod_value_remaining) - { - db->state_modify_op (db->cls, &scls->channel_key, - scls->mod_oper, scls->mod_name, - scls->mod_value, scls->mod_value_size); - GNUNET_free (scls->mod_name); - GNUNET_free (scls->mod_value); - scls->mod_oper = 0; - scls->mod_name = NULL; - scls->mod_value = NULL; - scls->mod_value_size = 0; - } - } - scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_MOD_CONT; - break; - - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA: - scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_DATA; - break; - - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: - scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_END; - break; - - default: - scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_ERROR; - } -} - - -static int -recv_state_fragment (void *cls, struct GNUNET_MULTICAST_MessageHeader *msg, - enum GNUNET_PSYCSTORE_MessageFlags flags) -{ - struct StateModifyClosure *scls = cls; - - if (NULL == scls->recv) - { - scls->recv = GNUNET_PSYC_receive_create (NULL, recv_state_message_part, - scls); - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "recv_state_fragment: %" PRIu64 "\n", GNUNET_ntohll (msg->fragment_id)); - - struct GNUNET_PSYC_MessageHeader * - pmsg = GNUNET_PSYC_message_header_create (msg, flags); - GNUNET_PSYC_receive_message (scls->recv, pmsg); - GNUNET_free (pmsg); - - return GNUNET_YES; -} - - -static void -handle_client_state_modify (void *cls, - const struct StateModifyRequest *req) -{ - struct GNUNET_SERVICE_Client *client = cls; - - uint64_t message_id = GNUNET_ntohll (req->message_id); - uint64_t state_delta = GNUNET_ntohll (req->state_delta); - uint64_t ret_frags = 0; - struct StateModifyClosure - scls = { .channel_key = req->channel_key }; - - int ret = db->state_modify_begin (db->cls, &req->channel_key, - message_id, state_delta); - - if (GNUNET_OK != ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Failed to begin modifying state: %d\n"), ret); - } - else - { - ret = db->message_get (db->cls, &req->channel_key, - message_id, message_id, 0, - &ret_frags, recv_state_fragment, &scls); - if (GNUNET_OK != ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Failed to modify state: %d\n"), ret); - GNUNET_break (0); - } - else - { - if (GNUNET_OK != db->state_modify_end (db->cls, &req->channel_key, message_id)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Failed to end modifying state!\n")); - GNUNET_break (0); - } - } - if (NULL != scls.recv) - { - GNUNET_PSYC_receive_destroy (scls.recv); - } - } - - send_result_code (client, req->op_id, ret, NULL); - GNUNET_SERVICE_client_continue (client); -} - - -static int -check_client_state_sync (void *cls, - const struct StateSyncRequest *req) -{ - return GNUNET_OK; -} - - -/** @todo FIXME: stop processing further state sync messages after an error */ -static void -handle_client_state_sync (void *cls, - const struct StateSyncRequest *req) -{ - struct GNUNET_SERVICE_Client *client = cls; - - int ret = GNUNET_SYSERR; - const char *name = (const char *) &req[1]; - uint16_t name_size = ntohs (req->name_size); - - if (name_size <= 2 || '\0' != name[name_size - 1]) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Tried to set invalid state variable name!\n")); - GNUNET_break_op (0); - } - else - { - ret = GNUNET_OK; - - if (req->flags & STATE_OP_FIRST) - { - ret = db->state_sync_begin (db->cls, &req->channel_key); - } - if (ret != GNUNET_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Failed to begin synchronizing state!\n")); - } - else - { - ret = db->state_sync_assign (db->cls, &req->channel_key, name, - name + ntohs (req->name_size), - ntohs (req->header.size) - sizeof (*req) - - ntohs (req->name_size)); - } - - if (GNUNET_OK == ret && req->flags & STATE_OP_LAST) - { - ret = db->state_sync_end (db->cls, &req->channel_key, - GNUNET_ntohll (req->max_state_message_id), - GNUNET_ntohll (req->state_hash_message_id)); - if (ret != GNUNET_OK) - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Failed to end synchronizing state!\n")); - } - } - send_result_code (client, req->op_id, ret, NULL); - GNUNET_SERVICE_client_continue (client); -} - - -static void -handle_client_state_reset (void *cls, - const struct OperationRequest *req) -{ - struct GNUNET_SERVICE_Client *client = cls; - - int ret = db->state_reset (db->cls, &req->channel_key); - - if (ret != GNUNET_OK) - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Failed to reset state!\n")); - - send_result_code (client, req->op_id, ret, NULL); - GNUNET_SERVICE_client_continue (client); -} - - -static void -handle_client_state_hash_update (void *cls, - const struct StateHashUpdateRequest *req) -{ - struct GNUNET_SERVICE_Client *client = cls; - - int ret = db->state_reset (db->cls, &req->channel_key); - if (ret != GNUNET_OK) - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Failed to reset state!\n")); - - send_result_code (client, req->op_id, ret, NULL); - GNUNET_SERVICE_client_continue (client); -} - - -static int -check_client_state_get (void *cls, - const struct OperationRequest *req) -{ - return GNUNET_OK; -} - - -static void -handle_client_state_get (void *cls, - const struct OperationRequest *req) -{ - struct GNUNET_SERVICE_Client *client = cls; - - struct SendClosure sc = { .op_id = req->op_id, .client = client }; - int64_t ret = GNUNET_SYSERR; - const char *name = (const char *) &req[1]; - uint16_t name_size = ntohs (req->header.size) - sizeof (*req); - - if (name_size <= 2 || '\0' != name[name_size - 1]) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Tried to get invalid state variable name!\n")); - GNUNET_break (0); - } - else - { - ret = db->state_get (db->cls, &req->channel_key, name, - &send_state_var, &sc); - if (GNUNET_NO == ret && name_size >= 5) /* min: _a_b\0 */ - { - char *p, *n = GNUNET_malloc (name_size); - GNUNET_memcpy (n, name, name_size); - while (&n[1] < (p = strrchr (n, '_')) && GNUNET_NO == ret) - { - *p = '\0'; - ret = db->state_get (db->cls, &req->channel_key, n, - &send_state_var, &sc); - } - GNUNET_free (n); - } - } - switch (ret) - { - case GNUNET_OK: - case GNUNET_NO: - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Failed to get state variable!\n")); - } - - send_result_code (client, req->op_id, ret, NULL); - GNUNET_SERVICE_client_continue (client); -} - - -static int -check_client_state_get_prefix (void *cls, - const struct OperationRequest *req) -{ - return GNUNET_OK; -} - - -static void -handle_client_state_get_prefix (void *cls, - const struct OperationRequest *req) -{ - struct GNUNET_SERVICE_Client *client = cls; - - struct SendClosure sc = { .op_id = req->op_id, .client = client }; - int64_t ret = GNUNET_SYSERR; - const char *name = (const char *) &req[1]; - uint16_t name_size = ntohs (req->header.size) - sizeof (*req); - - if (name_size <= 1 || '\0' != name[name_size - 1]) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Tried to get invalid state variable name!\n")); - GNUNET_break (0); - } - else - { - ret = db->state_get_prefix (db->cls, &req->channel_key, name, - &send_state_var, &sc); - } - switch (ret) - { - case GNUNET_OK: - case GNUNET_NO: - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Failed to get state variable!\n")); - } - - send_result_code (client, req->op_id, ret, NULL); - GNUNET_SERVICE_client_continue (client); -} - - -/** - * A new client connected. - * - * @param cls NULL - * @param client client to add - * @param mq message queue for @a client - * @return @a client - */ -static void * -client_notify_connect (void *cls, - struct GNUNET_SERVICE_Client *client, - struct GNUNET_MQ_Handle *mq) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client connected: %p\n", client); - - return client; -} - - -/** - * Called whenever a client is disconnected. - * Frees our resources associated with that client. - * - * @param cls closure - * @param client identification of the client - * @param app_ctx must match @a client - */ -static void -client_notify_disconnect (void *cls, - struct GNUNET_SERVICE_Client *client, - void *app_ctx) -{ -} - - -/** - * Initialize the PSYCstore service. - * - * @param cls Closure. - * @param server The initialized server. - * @param c Configuration to use. - */ -static void -run (void *cls, - const struct GNUNET_CONFIGURATION_Handle *c, - struct GNUNET_SERVICE_Handle *svc) -{ - cfg = c; - service = svc; - - /* Loading database plugin */ - char *database; - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, "psycstore", "database", - &database)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "psycstore", - "database"); - } - else - { - GNUNET_asprintf (&db_lib_name, - "libgnunet_plugin_psycstore_%s", - database); - db = GNUNET_PLUGIN_load (db_lib_name, (void *) cfg); - GNUNET_free (database); - } - if (NULL == db) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not load database backend `%s'\n", - db_lib_name); - GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); - return; - } - - stats = GNUNET_STATISTICS_create ("psycstore", cfg); - GNUNET_SCHEDULER_add_shutdown (shutdown_task, - NULL); -} - -/** - * Define "main" method using service macro. - */ -GNUNET_SERVICE_MAIN -("psycstore", - GNUNET_SERVICE_OPTION_NONE, - run, - client_notify_connect, - client_notify_disconnect, - NULL, - GNUNET_MQ_hd_fixed_size (client_membership_store, - GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_STORE, - struct MembershipStoreRequest, - NULL), - GNUNET_MQ_hd_fixed_size (client_membership_test, - GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_TEST, - struct MembershipTestRequest, - NULL), - GNUNET_MQ_hd_var_size (client_fragment_store, - GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_STORE, - struct FragmentStoreRequest, - NULL), - GNUNET_MQ_hd_fixed_size (client_fragment_get, - GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_GET, - struct FragmentGetRequest, - NULL), - GNUNET_MQ_hd_var_size (client_message_get, - GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET, - struct MessageGetRequest, - NULL), - GNUNET_MQ_hd_fixed_size (client_message_get_fragment, - GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET_FRAGMENT, - struct MessageGetFragmentRequest, - NULL), - GNUNET_MQ_hd_fixed_size (client_counters_get, - GNUNET_MESSAGE_TYPE_PSYCSTORE_COUNTERS_GET, - struct OperationRequest, - NULL), - GNUNET_MQ_hd_fixed_size (client_state_modify, - GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_MODIFY, - struct StateModifyRequest, - NULL), - GNUNET_MQ_hd_var_size (client_state_sync, - GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_SYNC, - struct StateSyncRequest, - NULL), - GNUNET_MQ_hd_fixed_size (client_state_reset, - GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_RESET, - struct OperationRequest, - NULL), - GNUNET_MQ_hd_fixed_size (client_state_hash_update, - GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_HASH_UPDATE, - struct StateHashUpdateRequest, - NULL), - GNUNET_MQ_hd_var_size (client_state_get, - GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_GET, - struct OperationRequest, - NULL), - GNUNET_MQ_hd_var_size (client_state_get_prefix, - GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_GET_PREFIX, - struct OperationRequest, - NULL)); - -/* end of gnunet-service-psycstore.c */ diff --git a/src/psycstore/plugin_psycstore_mysql.c b/src/psycstore/plugin_psycstore_mysql.c deleted file mode 100644 index c36b6f7a3..000000000 --- a/src/psycstore/plugin_psycstore_mysql.c +++ /dev/null @@ -1,1960 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file psycstore/plugin_psycstore_mysql.c - * @brief mysql-based psycstore backend - * @author Gabor X Toth - * @author Christian Grothoff - * @author Christophe Genevey - */ - -#include "platform.h" -#include "gnunet_psycstore_plugin.h" -#include "gnunet_psycstore_service.h" -#include "gnunet_multicast_service.h" -#include "gnunet_crypto_lib.h" -#include "gnunet_psyc_util_lib.h" -#include "psycstore.h" -#include "gnunet_my_lib.h" -#include "gnunet_mysql_lib.h" -#include - -/** - * After how many ms "busy" should a DB operation fail for good? A - * low value makes sure that we are more responsive to requests - * (especially PUTs). A high value guarantees a higher success rate - * (SELECTs in iterate can take several seconds despite LIMIT=1). - * - * The default value of 1s should ensure that users do not experience - * huge latencies while at the same time allowing operations to - * succeed with reasonable probability. - */ -#define BUSY_TIMEOUT_MS 1000 - -#define DEBUG_PSYCSTORE GNUNET_EXTRA_LOGGING - -/** - * Log an error message at log-level 'level' that indicates - * a failure of the command 'cmd' on file 'filename' - * with the message given by strerror(errno). - */ -#define LOG_MYSQL(db, level, cmd, stmt) \ - do { \ - GNUNET_log_from (level, "psycstore-mysql", \ - _("`%s' failed at %s:%d with error: %s\n"), \ - cmd, __FILE__, __LINE__, \ - mysql_stmt_error (GNUNET_MYSQL_statement_get_stmt(stmt))); \ - } while (0) - -#define LOG(kind,...) GNUNET_log_from (kind, "psycstore-mysql", __VA_ARGS__) - -enum Transactions { - TRANSACTION_NONE = 0, - TRANSACTION_STATE_MODIFY, - TRANSACTION_STATE_SYNC, -}; - -/** - * Context for all functions in this plugin. - */ -struct Plugin -{ - - const struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * MySQL context. - */ - struct GNUNET_MYSQL_Context *mc; - - /** - * Current transaction. - */ - enum Transactions transaction; - - /** - * Precompiled SQL for channel_key_store() - */ - struct GNUNET_MYSQL_StatementHandle *insert_channel_key; - - /** - * Precompiled SQL for slave_key_store() - */ - struct GNUNET_MYSQL_StatementHandle *insert_slave_key; - - /** - * Precompiled SQL for membership_store() - */ - struct GNUNET_MYSQL_StatementHandle *insert_membership; - - /** - * Precompiled SQL for membership_test() - */ - struct GNUNET_MYSQL_StatementHandle *select_membership; - - /** - * Precompiled SQL for fragment_store() - */ - struct GNUNET_MYSQL_StatementHandle *insert_fragment; - - /** - * Precompiled SQL for message_add_flags() - */ - struct GNUNET_MYSQL_StatementHandle *update_message_flags; - - /** - * Precompiled SQL for fragment_get() - */ - struct GNUNET_MYSQL_StatementHandle *select_fragments; - - /** - * Precompiled SQL for fragment_get() - */ - struct GNUNET_MYSQL_StatementHandle *select_latest_fragments; - - /** - * Precompiled SQL for message_get() - */ - struct GNUNET_MYSQL_StatementHandle *select_messages; - - /** - * Precompiled SQL for message_get() - */ - struct GNUNET_MYSQL_StatementHandle *select_latest_messages; - - /** - * Precompiled SQL for message_get_fragment() - */ - struct GNUNET_MYSQL_StatementHandle *select_message_fragment; - - /** - * Precompiled SQL for counters_get_message() - */ - struct GNUNET_MYSQL_StatementHandle *select_counters_message; - - /** - * Precompiled SQL for counters_get_state() - */ - struct GNUNET_MYSQL_StatementHandle *select_counters_state; - - /** - * Precompiled SQL for state_modify_end() - */ - struct GNUNET_MYSQL_StatementHandle *update_state_hash_message_id; - - /** - * Precompiled SQL for state_sync_end() - */ - struct GNUNET_MYSQL_StatementHandle *update_max_state_message_id; - - /** - * Precompiled SQL for state_modify_op() - */ - struct GNUNET_MYSQL_StatementHandle *insert_state_current; - - /** - * Precompiled SQL for state_modify_end() - */ - struct GNUNET_MYSQL_StatementHandle *delete_state_empty; - - /** - * Precompiled SQL for state_set_signed() - */ - struct GNUNET_MYSQL_StatementHandle *update_state_signed; - - /** - * Precompiled SQL for state_sync() - */ - struct GNUNET_MYSQL_StatementHandle *insert_state_sync; - - /** - * Precompiled SQL for state_sync() - */ - struct GNUNET_MYSQL_StatementHandle *delete_state; - - /** - * Precompiled SQL for state_sync() - */ - struct GNUNET_MYSQL_StatementHandle *insert_state_from_sync; - - /** - * Precompiled SQL for state_sync() - */ - struct GNUNET_MYSQL_StatementHandle *delete_state_sync; - - /** - * Precompiled SQL for state_get_signed() - */ - struct GNUNET_MYSQL_StatementHandle *select_state_signed; - - /** - * Precompiled SQL for state_get() - */ - struct GNUNET_MYSQL_StatementHandle *select_state_one; - - /** - * Precompiled SQL for state_get_prefix() - */ - struct GNUNET_MYSQL_StatementHandle *select_state_prefix; - -}; - -#if DEBUG_PSYCSTORE - -static void -mysql_trace (void *cls, const char *sql) -{ - LOG(GNUNET_ERROR_TYPE_DEBUG, "MYSQL query:\n%s\n", sql); -} - -#endif - - -/** - * @brief Prepare a SQL statement - * - * @param dbh handle to the database - * @param sql SQL statement, UTF-8 encoded - * @param stmt set to the prepared statement - * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure - */ -static int -mysql_prepare (struct GNUNET_MYSQL_Context *mc, - const char *sql, - struct GNUNET_MYSQL_StatementHandle **stmt) -{ - *stmt = GNUNET_MYSQL_statement_prepare (mc, - sql); - - if (NULL == *stmt) - { - LOG (GNUNET_ERROR_TYPE_ERROR, - _("Error preparing SQL query: %s\n %s\n"), - mysql_stmt_error (GNUNET_MYSQL_statement_get_stmt (*stmt)), - sql); - return GNUNET_SYSERR; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Prepared `%s' / %p\n", - sql, - stmt); - return GNUNET_OK; -} - - -/** - * Initialize the database connections and associated - * data structures (create tables and indices - * as needed as well). - * - * @param plugin the plugin context (state for this module) - * @return #GNUNET_OK on success - */ -static int -database_setup (struct Plugin *plugin) -{ - /* Open database and precompile statements */ - plugin->mc = GNUNET_MYSQL_context_create (plugin->cfg, - "psycstore-mysql"); - - if (NULL == plugin->mc) - { - LOG (GNUNET_ERROR_TYPE_ERROR, - _("Unable to initialize Mysql.\n")); - return GNUNET_SYSERR; - } - -#define STMT_RUN(sql) \ - if (GNUNET_OK != \ - GNUNET_MYSQL_statement_run (plugin->mc, \ - sql)) \ - { \ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, \ - _("Failed to run SQL statement `%s'\n"), \ - sql); \ - return GNUNET_SYSERR; \ - } - - /* Create tables */ - STMT_RUN ("CREATE TABLE IF NOT EXISTS channels (\n" - " id BIGINT UNSIGNED AUTO_INCREMENT,\n" - " pub_key BLOB(32),\n" - " max_state_message_id BIGINT UNSIGNED,\n" - " state_hash_message_id BIGINT UNSIGNED,\n" - " PRIMARY KEY(id),\n" - " UNIQUE KEY(pub_key(32))\n" - ");"); - - STMT_RUN ("CREATE TABLE IF NOT EXISTS slaves (\n" - " id BIGINT UNSIGNED AUTO_INCREMENT,\n" - " pub_key BLOB(32),\n" - " PRIMARY KEY(id),\n" - " UNIQUE KEY(pub_key(32))\n" - ");"); - - STMT_RUN ("CREATE TABLE IF NOT EXISTS membership (\n" - " channel_id BIGINT UNSIGNED NOT NULL REFERENCES channels(id),\n" - " slave_id BIGINT UNSIGNED NOT NULL REFERENCES slaves(id),\n" - " did_join TINYINT NOT NULL,\n" - " announced_at BIGINT UNSIGNED NOT NULL,\n" - " effective_since BIGINT UNSIGNED NOT NULL,\n" - " group_generation BIGINT UNSIGNED NOT NULL\n" - ");"); - -/*** FIX because IF NOT EXISTS doesn't work ***/ - GNUNET_MYSQL_statement_run (plugin->mc, - "CREATE INDEX idx_membership_channel_id_slave_id " - "ON membership (channel_id, slave_id);"); - - /** @todo messages table: add method_name column */ - STMT_RUN ("CREATE TABLE IF NOT EXISTS messages (\n" - " channel_id BIGINT UNSIGNED NOT NULL REFERENCES channels(id),\n" - " hop_counter BIGINT UNSIGNED NOT NULL,\n" - " signature BLOB,\n" - " purpose BLOB,\n" - " fragment_id BIGINT UNSIGNED NOT NULL,\n" - " fragment_offset BIGINT UNSIGNED NOT NULL,\n" - " message_id BIGINT UNSIGNED NOT NULL,\n" - " group_generation BIGINT UNSIGNED NOT NULL,\n" - " multicast_flags BIGINT UNSIGNED NOT NULL,\n" - " psycstore_flags BIGINT UNSIGNED NOT NULL,\n" - " data BLOB,\n" - " PRIMARY KEY (channel_id, fragment_id),\n" - " UNIQUE KEY(channel_id, message_id, fragment_offset)\n" - ");"); - - STMT_RUN ("CREATE TABLE IF NOT EXISTS state (\n" - " channel_id BIGINT UNSIGNED NOT NULL REFERENCES channels(id),\n" - " name TEXT NOT NULL,\n" - " value_current BLOB,\n" - " value_signed BLOB\n" - //" PRIMARY KEY (channel_id, name(255))\n" - ");"); - - STMT_RUN ("CREATE TABLE IF NOT EXISTS state_sync (\n" - " channel_id BIGINT UNSIGNED NOT NULL REFERENCES channels(id),\n" - " name TEXT NOT NULL,\n" - " value BLOB\n" - //" PRIMARY KEY (channel_id, name(255))\n" - ");"); -#undef STMT_RUN - - /* Prepare statements */ -#define PREP(stmt,handle) \ - if (GNUNET_OK != mysql_prepare (plugin->mc, stmt, handle)) \ - { \ - GNUNET_break (0); \ - return GNUNET_SYSERR; \ - } - PREP ("INSERT IGNORE INTO channels (pub_key) VALUES (?);", - &plugin->insert_channel_key); - PREP ("INSERT IGNORE INTO slaves (pub_key) VALUES (?);", - &plugin->insert_slave_key); - PREP ("INSERT INTO membership\n" - " (channel_id, slave_id, did_join, announced_at,\n" - " effective_since, group_generation)\n" - "VALUES ((SELECT id FROM channels WHERE pub_key = ?),\n" - " (SELECT id FROM slaves WHERE pub_key = ?),\n" - " ?, ?, ?, ?);", - &plugin->insert_membership); - PREP ("SELECT did_join FROM membership\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " AND slave_id = (SELECT id FROM slaves WHERE pub_key = ?)\n" - " AND effective_since <= ? AND did_join = 1\n" - "ORDER BY announced_at DESC LIMIT 1;", - &plugin->select_membership); - - PREP ("INSERT IGNORE INTO messages\n" - " (channel_id, hop_counter, signature, purpose,\n" - " fragment_id, fragment_offset, message_id,\n" - " group_generation, multicast_flags, psycstore_flags, data)\n" - "VALUES ((SELECT id FROM channels WHERE pub_key = ?),\n" - " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", - &plugin->insert_fragment); - - PREP ("UPDATE messages\n" - "SET psycstore_flags = psycstore_flags | ?\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " AND message_id = ? AND fragment_offset = 0;", - &plugin->update_message_flags); - - PREP ("SELECT hop_counter, signature, purpose, fragment_id,\n" - " fragment_offset, message_id, group_generation,\n" - " multicast_flags, psycstore_flags, data\n" - "FROM messages\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " AND ? <= fragment_id AND fragment_id <= ? LIMIT 1;", - &plugin->select_fragments); - - /** @todo select_messages: add method_prefix filter */ - PREP ("SELECT hop_counter, signature, purpose, fragment_id,\n" - " fragment_offset, message_id, group_generation,\n" - " multicast_flags, psycstore_flags, data\n" - "FROM messages\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " AND ? <= message_id AND message_id <= ?\n" - "LIMIT ?;", - &plugin->select_messages); - - PREP ("SELECT * FROM\n" - "(SELECT hop_counter, signature, purpose, fragment_id,\n" - " fragment_offset, message_id, group_generation,\n" - " multicast_flags, psycstore_flags, data\n" - " FROM messages\n" - " WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " ORDER BY fragment_id DESC\n" - " LIMIT ?)\n" - "ORDER BY fragment_id;", - &plugin->select_latest_fragments); - - /** @todo select_latest_messages: add method_prefix filter */ - PREP ("SELECT hop_counter, signature, purpose, fragment_id,\n" - " fragment_offset, message_id, group_generation,\n" - " multicast_flags, psycstore_flags, data\n" - "FROM messages\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " AND message_id IN\n" - " (SELECT message_id\n" - " FROM messages\n" - " WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " GROUP BY message_id\n" - " ORDER BY message_id\n" - " DESC LIMIT ?)\n" - "ORDER BY fragment_id;", - &plugin->select_latest_messages); - - PREP ("SELECT hop_counter, signature, purpose, fragment_id,\n" - " fragment_offset, message_id, group_generation,\n" - " multicast_flags, psycstore_flags, data\n" - "FROM messages\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " AND message_id = ? AND fragment_offset = ?;", - &plugin->select_message_fragment); - - PREP ("SELECT fragment_id, message_id, group_generation\n" - "FROM messages\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - "ORDER BY fragment_id DESC LIMIT 1;", - &plugin->select_counters_message); - - PREP ("SELECT max_state_message_id\n" - "FROM channels\n" - "WHERE pub_key = ? AND max_state_message_id IS NOT NULL;", - &plugin->select_counters_state); - - PREP ("UPDATE channels\n" - "SET max_state_message_id = ?\n" - "WHERE pub_key = ?;", - &plugin->update_max_state_message_id); - - PREP ("UPDATE channels\n" - "SET state_hash_message_id = ?\n" - "WHERE pub_key = ?;", - &plugin->update_state_hash_message_id); - - PREP ("REPLACE INTO state\n" - " (channel_id, name, value_current, value_signed)\n" - "SELECT new.channel_id, new.name, new.value_current, old.value_signed\n" - "FROM (SELECT (SELECT id FROM channels WHERE pub_key = ?) AS channel_id,\n" - " (SELECT ?) AS name,\n" - " (SELECT ?) AS value_current\n" - " ) AS new\n" - "LEFT JOIN (SELECT channel_id, name, value_signed\n" - " FROM state) AS old\n" - "ON new.channel_id = old.channel_id AND new.name = old.name;", - &plugin->insert_state_current); - - PREP ("DELETE FROM state\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " AND (value_current IS NULL OR length(value_current) = 0)\n" - " AND (value_signed IS NULL OR length(value_signed) = 0);", - &plugin->delete_state_empty); - - PREP ("UPDATE state\n" - "SET value_signed = value_current\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);", - &plugin->update_state_signed); - - PREP ("DELETE FROM state\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);", - &plugin->delete_state); - - PREP ("INSERT INTO state_sync (channel_id, name, value)\n" - "VALUES ((SELECT id FROM channels WHERE pub_key = ?), ?, ?);", - &plugin->insert_state_sync); - - PREP ("INSERT INTO state\n" - " (channel_id, name, value_current, value_signed)\n" - "SELECT channel_id, name, value, value\n" - "FROM state_sync\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);", - &plugin->insert_state_from_sync); - - PREP ("DELETE FROM state_sync\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);", - &plugin->delete_state_sync); - - PREP ("SELECT value_current\n" - "FROM state\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " AND name = ?;", - &plugin->select_state_one); - - PREP ("SELECT name, value_current\n" - "FROM state\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " AND (name = ? OR substr(name, 1, ?) = ?);", - &plugin->select_state_prefix); - - PREP ("SELECT name, value_signed\n" - "FROM state\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)" - " AND value_signed IS NOT NULL;", - &plugin->select_state_signed); -#undef PREP - - return GNUNET_OK; -} - - -/** - * Shutdown database connection and associate data - * structures. - * @param plugin the plugin context (state for this module) - */ -static void -database_shutdown (struct Plugin *plugin) -{ - GNUNET_MYSQL_context_destroy (plugin->mc); -} - - -/** - * Execute a prepared statement with a @a channel_key argument. - * - * @param plugin Plugin handle. - * @param stmt Statement to execute. - * @param channel_key Public key of the channel. - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -exec_channel (struct Plugin *plugin, struct GNUNET_MYSQL_StatementHandle *stmt, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) -{ - struct GNUNET_MY_QueryParam params[] = { - GNUNET_MY_query_param_auto_from_type (channel_key), - GNUNET_MY_query_param_end - }; - - if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params)) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql exec_channel", stmt); - } - - if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql_stmt_reset", stmt); - return GNUNET_SYSERR; - } - - return GNUNET_OK; -} - - -/** - * Begin a transaction. - */ -static int -transaction_begin (struct Plugin *plugin, enum Transactions transaction) -{ - if (GNUNET_OK != GNUNET_MYSQL_statement_run (plugin->mc, "BEGIN")) - { - LOG(GNUNET_ERROR_TYPE_ERROR, "transaction_begin failed"); - return GNUNET_SYSERR; - } - - plugin->transaction = transaction; - return GNUNET_OK; -} - - -/** - * Commit current transaction. - */ -static int -transaction_commit (struct Plugin *plugin) -{ - if (GNUNET_OK != GNUNET_MYSQL_statement_run (plugin->mc, "COMMIT")) - { - LOG(GNUNET_ERROR_TYPE_ERROR, "transaction_commit failed"); - return GNUNET_SYSERR; - } - - plugin->transaction = TRANSACTION_NONE; - return GNUNET_OK; -} - - -/** - * Roll back current transaction. - */ -static int -transaction_rollback (struct Plugin *plugin) -{ - if (GNUNET_OK != GNUNET_MYSQL_statement_run (plugin->mc, "ROLLBACK")) - { - LOG(GNUNET_ERROR_TYPE_ERROR, "transaction_rollback failed"); - return GNUNET_SYSERR; - } - - plugin->transaction = TRANSACTION_NONE; - return GNUNET_OK; -} - - -static int -channel_key_store (struct Plugin *plugin, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) -{ - struct GNUNET_MYSQL_StatementHandle *stmt = plugin->insert_channel_key; - - struct GNUNET_MY_QueryParam params[] = { - GNUNET_MY_query_param_auto_from_type (channel_key), - GNUNET_MY_query_param_end - }; - - if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params)) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql exec_prepared", stmt); - return GNUNET_SYSERR; - } - - if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql_stmt_reset", stmt); - return GNUNET_SYSERR; - } - - return GNUNET_OK; -} - - -static int -slave_key_store (struct Plugin *plugin, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key) -{ - struct GNUNET_MYSQL_StatementHandle *stmt = plugin->insert_slave_key; - - struct GNUNET_MY_QueryParam params[] = { - GNUNET_MY_query_param_auto_from_type (slave_key), - GNUNET_MY_query_param_end - }; - - if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params)) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql exec_prepared", stmt); - return GNUNET_SYSERR; - } - - if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql_stmt_reset", stmt); - return GNUNET_SYSERR; - } - - return GNUNET_OK; -} - - -/** - * Store join/leave events for a PSYC channel in order to be able to answer - * membership test queries later. - * - * @see GNUNET_PSYCSTORE_membership_store() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -mysql_membership_store (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - int did_join, - uint64_t announced_at, - uint64_t effective_since, - uint64_t group_generation) -{ - struct Plugin *plugin = cls; - - uint32_t idid_join = (uint32_t)did_join; - - struct GNUNET_MYSQL_StatementHandle *stmt = plugin->insert_membership; - - GNUNET_assert (TRANSACTION_NONE == plugin->transaction); - - if (announced_at > INT64_MAX || - effective_since > INT64_MAX || - group_generation > INT64_MAX) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != channel_key_store (plugin, channel_key) - || GNUNET_OK != slave_key_store (plugin, slave_key)) - return GNUNET_SYSERR; - - struct GNUNET_MY_QueryParam params[] = { - GNUNET_MY_query_param_auto_from_type (channel_key), - GNUNET_MY_query_param_auto_from_type (slave_key), - GNUNET_MY_query_param_uint32 (&idid_join), - GNUNET_MY_query_param_uint64 (&announced_at), - GNUNET_MY_query_param_uint64 (&effective_since), - GNUNET_MY_query_param_uint64 (&group_generation), - GNUNET_MY_query_param_end - }; - - if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params)) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql exec_prepared", stmt); - return GNUNET_SYSERR; - } - - if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql_stmt_reset", stmt); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - -/** - * Test if a member was admitted to the channel at the given message ID. - * - * @see GNUNET_PSYCSTORE_membership_test() - * - * @return #GNUNET_YES if the member was admitted, #GNUNET_NO if not, - * #GNUNET_SYSERR if there was en error. - */ -static int -membership_test (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - uint64_t message_id) -{ - struct Plugin *plugin = cls; - - struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_membership; - - uint32_t did_join = 0; - - int ret = GNUNET_SYSERR; - - struct GNUNET_MY_QueryParam params_select[] = { - GNUNET_MY_query_param_auto_from_type (channel_key), - GNUNET_MY_query_param_auto_from_type (slave_key), - GNUNET_MY_query_param_uint64 (&message_id), - GNUNET_MY_query_param_end - }; - - if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select)) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql execute prepared", stmt); - return GNUNET_SYSERR; - } - - struct GNUNET_MY_ResultSpec results_select[] = { - GNUNET_MY_result_spec_uint32 (&did_join), - GNUNET_MY_result_spec_end - }; - - switch (GNUNET_MY_extract_result (stmt, results_select)) - { - case GNUNET_NO: - ret = GNUNET_NO; - break; - case GNUNET_OK: - ret = GNUNET_YES; - break; - default: - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql extract_result", stmt); - return GNUNET_SYSERR; - } - - if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql_stmt_reset", stmt); - return GNUNET_SYSERR; - } - - return ret; -} - -/** - * Store a message fragment sent to a channel. - * - * @see GNUNET_PSYCSTORE_fragment_store() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -fragment_store (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_MULTICAST_MessageHeader *msg, - uint32_t psycstore_flags) -{ - struct Plugin *plugin = cls; - - struct GNUNET_MYSQL_StatementHandle *stmt = plugin->insert_fragment; - - GNUNET_assert (TRANSACTION_NONE == plugin->transaction); - - uint64_t fragment_id = GNUNET_ntohll (msg->fragment_id); - - uint64_t fragment_offset = GNUNET_ntohll (msg->fragment_offset); - uint64_t message_id = GNUNET_ntohll (msg->message_id); - uint64_t group_generation = GNUNET_ntohll (msg->group_generation); - - uint64_t hop_counter = ntohl(msg->hop_counter); - uint64_t flags = ntohl(msg->flags); - - if (fragment_id > INT64_MAX || fragment_offset > INT64_MAX || - message_id > INT64_MAX || group_generation > INT64_MAX) - { - LOG(GNUNET_ERROR_TYPE_ERROR, - "Tried to store fragment with a field > INT64_MAX: " - "%lu, %lu, %lu, %lu\n", fragment_id, fragment_offset, - message_id, group_generation); - GNUNET_break (0); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != channel_key_store (plugin, channel_key)) - return GNUNET_SYSERR; - - struct GNUNET_MY_QueryParam params_insert[] = { - GNUNET_MY_query_param_auto_from_type (channel_key), - GNUNET_MY_query_param_uint64 (&hop_counter), - GNUNET_MY_query_param_auto_from_type (&msg->signature), - GNUNET_MY_query_param_auto_from_type (&msg->purpose), - GNUNET_MY_query_param_uint64 (&fragment_id), - GNUNET_MY_query_param_uint64 (&fragment_offset), - GNUNET_MY_query_param_uint64 (&message_id), - GNUNET_MY_query_param_uint64 (&group_generation), - GNUNET_MY_query_param_uint64 (&flags), - GNUNET_MY_query_param_uint32 (&psycstore_flags), - GNUNET_MY_query_param_fixed_size (&msg[1], ntohs (msg->header.size) - - sizeof (*msg)), - GNUNET_MY_query_param_end - }; - - if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_insert)) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql execute prepared", stmt); - return GNUNET_SYSERR; - } - - if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql_stmt_reset", stmt); - return GNUNET_SYSERR; - } - - return GNUNET_OK; -} - -/** - * Set additional flags for a given message. - * - * They are OR'd with any existing flags set. - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -message_add_flags (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id, - uint32_t psycstore_flags) -{ - struct Plugin *plugin = cls; - struct GNUNET_MYSQL_StatementHandle *stmt = plugin->update_message_flags; - - int sql_ret; - int ret = GNUNET_SYSERR; - - struct GNUNET_MY_QueryParam params_update[] = { - GNUNET_MY_query_param_uint32 (&psycstore_flags), - GNUNET_MY_query_param_auto_from_type (channel_key), - GNUNET_MY_query_param_uint64 (&message_id), - GNUNET_MY_query_param_end - }; - - sql_ret = GNUNET_MY_exec_prepared (plugin->mc, stmt, params_update); - switch (sql_ret) - { - case GNUNET_OK: - ret = GNUNET_OK; - break; - - default: - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql execute prepared", stmt); - } - - if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql_stmt_reset", stmt); - return GNUNET_SYSERR; - } - - return ret; -} - - -static int -fragment_row (struct GNUNET_MYSQL_StatementHandle *stmt, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls, - uint64_t *returned_fragments) -{ - - uint32_t hop_counter; - void *signature = NULL; - void *purpose = NULL; - size_t signature_size; - size_t purpose_size; - uint64_t fragment_id; - uint64_t fragment_offset; - uint64_t message_id; - uint64_t group_generation; - uint64_t flags; - void *buf; - size_t buf_size; - int ret = GNUNET_SYSERR; - int sql_ret; - struct GNUNET_MULTICAST_MessageHeader *mp; - uint64_t msg_flags; - struct GNUNET_MY_ResultSpec results[] = { - GNUNET_MY_result_spec_uint32 (&hop_counter), - GNUNET_MY_result_spec_variable_size (&signature, &signature_size), - GNUNET_MY_result_spec_variable_size (&purpose, &purpose_size), - GNUNET_MY_result_spec_uint64 (&fragment_id), - GNUNET_MY_result_spec_uint64 (&fragment_offset), - GNUNET_MY_result_spec_uint64 (&message_id), - GNUNET_MY_result_spec_uint64 (&group_generation), - GNUNET_MY_result_spec_uint64 (&msg_flags), - GNUNET_MY_result_spec_uint64 (&flags), - GNUNET_MY_result_spec_variable_size (&buf, - &buf_size), - GNUNET_MY_result_spec_end - }; - - do - { - sql_ret = GNUNET_MY_extract_result (stmt, results); - switch (sql_ret) - { - case GNUNET_NO: - if (ret != GNUNET_YES) - ret = GNUNET_NO; - break; - - case GNUNET_YES: - mp = GNUNET_malloc (sizeof (*mp) + buf_size); - - mp->header.size = htons (sizeof (*mp) + buf_size); - mp->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE); - mp->hop_counter = htonl (hop_counter); - GNUNET_memcpy (&mp->signature, - signature, - signature_size); - GNUNET_memcpy (&mp->purpose, - purpose, - purpose_size); - mp->fragment_id = GNUNET_htonll (fragment_id); - mp->fragment_offset = GNUNET_htonll (fragment_offset); - mp->message_id = GNUNET_htonll (message_id); - mp->group_generation = GNUNET_htonll (group_generation); - mp->flags = htonl(msg_flags); - - GNUNET_memcpy (&mp[1], - buf, - buf_size); - ret = cb (cb_cls, mp, (enum GNUNET_PSYCSTORE_MessageFlags) flags); - if (NULL != returned_fragments) - (*returned_fragments)++; - GNUNET_MY_cleanup_result (results); - break; - - default: - LOG_MYSQL (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql extract_result", stmt); - } - } - while (GNUNET_YES == sql_ret); - - // for debugging - if (GNUNET_NO == ret) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, - "Empty result set\n"); - - return ret; -} - - -static int -fragment_select (struct Plugin *plugin, - struct GNUNET_MYSQL_StatementHandle *stmt, - struct GNUNET_MY_QueryParam *params, - uint64_t *returned_fragments, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls) -{ - int ret = GNUNET_SYSERR; - int sql_ret; - - sql_ret = GNUNET_MY_exec_prepared (plugin->mc, stmt, params); - switch (sql_ret) - { - case GNUNET_NO: - if (ret != GNUNET_YES) - ret = GNUNET_NO; - break; - - case GNUNET_YES: - ret = fragment_row (stmt, cb, cb_cls, returned_fragments); - break; - - default: - LOG_MYSQL (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql exec_prepared", stmt); - } - return ret; -} - - -/** - * Retrieve a message fragment range by fragment ID. - * - * @see GNUNET_PSYCSTORE_fragment_get() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -fragment_get (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t first_fragment_id, - uint64_t last_fragment_id, - uint64_t *returned_fragments, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls) -{ - struct Plugin *plugin = cls; - struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_fragments; - int ret = GNUNET_SYSERR; - struct GNUNET_MY_QueryParam params_select[] = { - GNUNET_MY_query_param_auto_from_type (channel_key), - GNUNET_MY_query_param_uint64 (&first_fragment_id), - GNUNET_MY_query_param_uint64 (&last_fragment_id), - GNUNET_MY_query_param_end - }; - - *returned_fragments = 0; - ret = fragment_select (plugin, stmt, params_select, returned_fragments, cb, cb_cls); - - if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) - { - LOG_MYSQL (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql_stmt_reset", stmt); - return GNUNET_SYSERR; - } - - return ret; -} - - -/** - * Retrieve a message fragment range by fragment ID. - * - * @see GNUNET_PSYCSTORE_fragment_get_latest() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -fragment_get_latest (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t fragment_limit, - uint64_t *returned_fragments, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls) -{ - struct Plugin *plugin = cls; - - struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_latest_fragments; - - int ret = GNUNET_SYSERR; - *returned_fragments = 0; - - struct GNUNET_MY_QueryParam params_select[] = { - GNUNET_MY_query_param_auto_from_type (channel_key), - GNUNET_MY_query_param_uint64 (&fragment_limit), - GNUNET_MY_query_param_end - }; - - ret = fragment_select (plugin, stmt, params_select, returned_fragments, cb, cb_cls); - - if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql_stmt_reset", stmt); - return GNUNET_SYSERR; - } - - return ret; -} - - -/** - * Retrieve all fragments of a message ID range. - * - * @see GNUNET_PSYCSTORE_message_get() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -message_get (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t first_message_id, - uint64_t last_message_id, - uint64_t fragment_limit, - uint64_t *returned_fragments, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls) -{ - struct Plugin *plugin = cls; - struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_messages; - int ret; - - if (0 == fragment_limit) - fragment_limit = UINT64_MAX; - - struct GNUNET_MY_QueryParam params_select[] = { - GNUNET_MY_query_param_auto_from_type (channel_key), - GNUNET_MY_query_param_uint64 (&first_message_id), - GNUNET_MY_query_param_uint64 (&last_message_id), - GNUNET_MY_query_param_uint64 (&fragment_limit), - GNUNET_MY_query_param_end - }; - - *returned_fragments = 0; - ret = fragment_select (plugin, stmt, params_select, returned_fragments, cb, cb_cls); - - if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql_stmt_reset", stmt); - return GNUNET_SYSERR; - } - - return ret; -} - - -/** - * Retrieve all fragments of the latest messages. - * - * @see GNUNET_PSYCSTORE_message_get_latest() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -message_get_latest (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_limit, - uint64_t *returned_fragments, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls) -{ - struct Plugin *plugin = cls; - - struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_latest_messages; - - int ret = GNUNET_SYSERR; - *returned_fragments = 0; - - struct GNUNET_MY_QueryParam params_select[] = { - GNUNET_MY_query_param_auto_from_type (channel_key), - GNUNET_MY_query_param_auto_from_type (channel_key), - GNUNET_MY_query_param_uint64 (&message_limit), - GNUNET_MY_query_param_end - }; - - ret = fragment_select (plugin, stmt, params_select, returned_fragments, cb, cb_cls); - - if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql_stmt_reset", stmt); - return GNUNET_SYSERR; - } - - return ret; -} - - -/** - * Retrieve a fragment of message specified by its message ID and fragment - * offset. - * - * @see GNUNET_PSYCSTORE_message_get_fragment() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -message_get_fragment (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id, - uint64_t fragment_offset, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls) -{ - struct Plugin *plugin = cls; - struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_message_fragment; - int sql_ret; - int ret = GNUNET_SYSERR; - - struct GNUNET_MY_QueryParam params_select[] = { - GNUNET_MY_query_param_auto_from_type (channel_key), - GNUNET_MY_query_param_uint64 (&message_id), - GNUNET_MY_query_param_uint64 (&fragment_offset), - GNUNET_MY_query_param_end - }; - - sql_ret = GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select); - switch (sql_ret) - { - case GNUNET_NO: - ret = GNUNET_NO; - break; - - case GNUNET_OK: - ret = fragment_row (stmt, cb, cb_cls, NULL); - break; - - default: - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql execute prepared", stmt); - } - - if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql_stmt_reset", stmt); - return GNUNET_SYSERR; - } - - return ret; -} - -/** - * Retrieve the max. values of message counters for a channel. - * - * @see GNUNET_PSYCSTORE_counters_get() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -counters_message_get (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t *max_fragment_id, - uint64_t *max_message_id, - uint64_t *max_group_generation) -{ - struct Plugin *plugin = cls; - - struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_counters_message; - - int ret = GNUNET_SYSERR; - - struct GNUNET_MY_QueryParam params_select[] = { - GNUNET_MY_query_param_auto_from_type (channel_key), - GNUNET_MY_query_param_end - }; - - if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select)) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql execute prepared", stmt); - return GNUNET_SYSERR; - } - - struct GNUNET_MY_ResultSpec results_select[] = { - GNUNET_MY_result_spec_uint64 (max_fragment_id), - GNUNET_MY_result_spec_uint64 (max_message_id), - GNUNET_MY_result_spec_uint64 (max_group_generation), - GNUNET_MY_result_spec_end - }; - - ret = GNUNET_MY_extract_result (stmt, results_select); - - if (GNUNET_OK != ret) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql extract_result", stmt); - return GNUNET_SYSERR; - } - - if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql_stmt_reset", stmt); - return GNUNET_SYSERR; - } - - return ret; -} - -/** - * Retrieve the max. values of state counters for a channel. - * - * @see GNUNET_PSYCSTORE_counters_get() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -counters_state_get (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t *max_state_message_id) -{ - struct Plugin *plugin = cls; - - struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_counters_state; - - int ret = GNUNET_SYSERR; - - struct GNUNET_MY_QueryParam params_select[] = { - GNUNET_MY_query_param_auto_from_type (channel_key), - GNUNET_MY_query_param_end - }; - - if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select)) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql execute prepared", stmt); - return GNUNET_SYSERR; - } - - struct GNUNET_MY_ResultSpec results_select[] = { - GNUNET_MY_result_spec_uint64 (max_state_message_id), - GNUNET_MY_result_spec_end - }; - - ret = GNUNET_MY_extract_result (stmt, results_select); - - if (GNUNET_OK != ret) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql extract_result", stmt); - return GNUNET_SYSERR; - } - - if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql_stmt_reset", stmt); - return GNUNET_SYSERR; - } - - return ret; -} - - -/** - * Assign a value to a state variable. - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_assign (struct Plugin *plugin, struct GNUNET_MYSQL_StatementHandle *stmt, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const char *name, const void *value, size_t value_size) -{ - int ret = GNUNET_SYSERR; - - struct GNUNET_MY_QueryParam params[] = { - GNUNET_MY_query_param_auto_from_type (channel_key), - GNUNET_MY_query_param_string (name), - GNUNET_MY_query_param_fixed_size(value, value_size), - GNUNET_MY_query_param_end - }; - - ret = GNUNET_MY_exec_prepared (plugin->mc, stmt, params); - if (GNUNET_OK != ret) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql exec_prepared", stmt); - return GNUNET_SYSERR; - } - - if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql_stmt_reset", stmt); - return GNUNET_SYSERR; - } - - return ret; -} - - -static int -update_message_id (struct Plugin *plugin, struct GNUNET_MYSQL_StatementHandle *stmt, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id) -{ - struct GNUNET_MY_QueryParam params[] = { - GNUNET_MY_query_param_uint64 (&message_id), - GNUNET_MY_query_param_auto_from_type (channel_key), - GNUNET_MY_query_param_end - }; - - if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, - stmt, - params)) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql execute prepared", stmt); - return GNUNET_SYSERR; - } - - if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql_stmt_reset", stmt); - return GNUNET_SYSERR; - } - - return GNUNET_OK; -} - - -/** - * Begin modifying current state. - */ -static int -state_modify_begin (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id, uint64_t state_delta) -{ - struct Plugin *plugin = cls; - - if (state_delta > 0) - { - /** - * We can only apply state modifiers in the current message if modifiers in - * the previous stateful message (message_id - state_delta) were already - * applied. - */ - - uint64_t max_state_message_id = 0; - int ret = counters_state_get (plugin, channel_key, &max_state_message_id); - switch (ret) - { - case GNUNET_OK: - case GNUNET_NO: // no state yet - ret = GNUNET_OK; - break; - default: - return ret; - } - - if (max_state_message_id < message_id - state_delta) - return GNUNET_NO; /* some stateful messages not yet applied */ - else if (message_id - state_delta < max_state_message_id) - return GNUNET_NO; /* changes already applied */ - } - - if (TRANSACTION_NONE != plugin->transaction) - { - /** @todo FIXME: wait for other transaction to finish */ - return GNUNET_SYSERR; - } - return transaction_begin (plugin, TRANSACTION_STATE_MODIFY); -} - - -/** - * Set the current value of state variable. - * - * @see GNUNET_PSYCSTORE_state_modify() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_modify_op (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - enum GNUNET_PSYC_Operator op, - const char *name, const void *value, size_t value_size) -{ - struct Plugin *plugin = cls; - GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction); - - switch (op) - { - case GNUNET_PSYC_OP_ASSIGN: - return state_assign (plugin, plugin->insert_state_current, - channel_key, name, value, value_size); - - default: /** @todo implement more state operations */ - GNUNET_break (0); - return GNUNET_SYSERR; - } -} - - -/** - * End modifying current state. - */ -static int -state_modify_end (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id) -{ - struct Plugin *plugin = cls; - GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction); - - return - GNUNET_OK == exec_channel (plugin, plugin->delete_state_empty, channel_key) - && GNUNET_OK == update_message_id (plugin, - plugin->update_max_state_message_id, - channel_key, message_id) - && GNUNET_OK == transaction_commit (plugin) - ? GNUNET_OK : GNUNET_SYSERR; -} - - -/** - * Begin state synchronization. - */ -static int -state_sync_begin (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) -{ - struct Plugin *plugin = cls; - return exec_channel (plugin, plugin->delete_state_sync, channel_key); -} - - -/** - * Assign current value of a state variable. - * - * @see GNUNET_PSYCSTORE_state_modify() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_sync_assign (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const char *name, const void *value, size_t value_size) -{ - struct Plugin *plugin = cls; - return state_assign (cls, plugin->insert_state_sync, - channel_key, name, value, value_size); -} - - -/** - * End modifying current state. - */ -static int -state_sync_end (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t max_state_message_id, - uint64_t state_hash_message_id) -{ - struct Plugin *plugin = cls; - int ret = GNUNET_SYSERR; - - if (TRANSACTION_NONE != plugin->transaction) - { - /** @todo FIXME: wait for other transaction to finish */ - return GNUNET_SYSERR; - } - - GNUNET_OK == transaction_begin (plugin, TRANSACTION_STATE_SYNC) - && GNUNET_OK == exec_channel (plugin, plugin->delete_state, channel_key) - && GNUNET_OK == exec_channel (plugin, plugin->insert_state_from_sync, - channel_key) - && GNUNET_OK == exec_channel (plugin, plugin->delete_state_sync, - channel_key) - && GNUNET_OK == update_message_id (plugin, - plugin->update_state_hash_message_id, - channel_key, state_hash_message_id) - && GNUNET_OK == update_message_id (plugin, - plugin->update_max_state_message_id, - channel_key, max_state_message_id) - && GNUNET_OK == transaction_commit (plugin) - ? ret = GNUNET_OK - : transaction_rollback (plugin); - return ret; -} - - -/** - * Delete the whole state. - * - * @see GNUNET_PSYCSTORE_state_reset() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_reset (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) -{ - struct Plugin *plugin = cls; - return exec_channel (plugin, plugin->delete_state, channel_key); -} - - -/** - * Update signed values of state variables in the state store. - * - * @see GNUNET_PSYCSTORE_state_hash_update() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_update_signed (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) -{ - struct Plugin *plugin = cls; - return exec_channel (plugin, plugin->update_state_signed, channel_key); -} - - -/** - * Retrieve a state variable by name. - * - * @see GNUNET_PSYCSTORE_state_get() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_get (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const char *name, GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls) -{ - struct Plugin *plugin = cls; - int ret = GNUNET_SYSERR; - int sql_ret ; - - struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_state_one; - - struct GNUNET_MY_QueryParam params_select[] = { - GNUNET_MY_query_param_auto_from_type (channel_key), - GNUNET_MY_query_param_string (name), - GNUNET_MY_query_param_end - }; - - void *value_current = NULL; - size_t value_size = 0; - - struct GNUNET_MY_ResultSpec results[] = { - GNUNET_MY_result_spec_variable_size (&value_current, &value_size), - GNUNET_MY_result_spec_end - }; - - if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select)) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql exec_prepared", stmt); - } - else - { - sql_ret = GNUNET_MY_extract_result (stmt, results); - switch (sql_ret) - { - case GNUNET_NO: - ret = GNUNET_NO; - break; - - case GNUNET_YES: - ret = cb (cb_cls, name, value_current, value_size); - break; - - default: - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql extract_result", stmt); - } - } - - if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql_stmt_reset", stmt); - return GNUNET_SYSERR; - } - - return ret; -} - - -/** - * Retrieve all state variables for a channel with the given prefix. - * - * @see GNUNET_PSYCSTORE_state_get_prefix() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_get_prefix (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const char *name, GNUNET_PSYCSTORE_StateCallback cb, - void *cb_cls) -{ - struct Plugin *plugin = cls; - int ret = GNUNET_SYSERR; - - struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_state_prefix; - - uint32_t name_len = (uint32_t) strlen (name); - - struct GNUNET_MY_QueryParam params_select[] = { - GNUNET_MY_query_param_auto_from_type (channel_key), - GNUNET_MY_query_param_string (name), - GNUNET_MY_query_param_uint32 (&name_len), - GNUNET_MY_query_param_string (name), - GNUNET_MY_query_param_end - }; - - char *name2 = ""; - void *value_current = NULL; - size_t value_size = 0; - - struct GNUNET_MY_ResultSpec results[] = { - GNUNET_MY_result_spec_string (&name2), - GNUNET_MY_result_spec_variable_size (&value_current, &value_size), - GNUNET_MY_result_spec_end - };; - - int sql_ret; - - if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select)) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql exec_prepared", stmt); - return GNUNET_SYSERR; - } - - do - { - sql_ret = GNUNET_MY_extract_result (stmt, results); - switch (sql_ret) - { - case GNUNET_NO: - if (ret != GNUNET_YES) - ret = GNUNET_NO; - break; - - case GNUNET_YES: - ret = cb (cb_cls, (const char *) name2, value_current, value_size); - - if (ret != GNUNET_YES) - sql_ret = GNUNET_NO; - break; - - default: - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql extract_result", stmt); - } - } - while (sql_ret == GNUNET_YES); - - if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql_stmt_reset", stmt); - return GNUNET_SYSERR; - } - - return ret; -} - - -/** - * Retrieve all signed state variables for a channel. - * - * @see GNUNET_PSYCSTORE_state_get_signed() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_get_signed (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls) -{ - struct Plugin *plugin = cls; - int ret = GNUNET_SYSERR; - - struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_state_signed; - - struct GNUNET_MY_QueryParam params_select[] = { - GNUNET_MY_query_param_auto_from_type (channel_key), - GNUNET_MY_query_param_end - }; - - int sql_ret; - - char *name = ""; - void *value_signed = NULL; - size_t value_size = 0; - - struct GNUNET_MY_ResultSpec results[] = { - GNUNET_MY_result_spec_string (&name), - GNUNET_MY_result_spec_variable_size (&value_signed, &value_size), - GNUNET_MY_result_spec_end - }; - - if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select)) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql exec_prepared", stmt); - return GNUNET_SYSERR; - } - - do - { - sql_ret = GNUNET_MY_extract_result (stmt, results); - switch (sql_ret) - { - case GNUNET_NO: - if (ret != GNUNET_YES) - ret = GNUNET_NO; - break; - - case GNUNET_YES: - ret = cb (cb_cls, (const char *) name, value_signed, value_size); - - if (ret != GNUNET_YES) - sql_ret = GNUNET_NO; - break; - - default: - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql extract_result", stmt); - } - } - while (sql_ret == GNUNET_YES); - - if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) - { - LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "mysql_stmt_reset", stmt); - return GNUNET_SYSERR; - } - - return ret; -} - - -/** - * Entry point for the plugin. - * - * @param cls The struct GNUNET_CONFIGURATION_Handle. - * @return NULL on error, otherwise the plugin context - */ -void * -libgnunet_plugin_psycstore_mysql_init (void *cls) -{ - static struct Plugin plugin; - const struct GNUNET_CONFIGURATION_Handle *cfg = cls; - struct GNUNET_PSYCSTORE_PluginFunctions *api; - - if (NULL != plugin.cfg) - return NULL; /* can only initialize once! */ - memset (&plugin, 0, sizeof (struct Plugin)); - plugin.cfg = cfg; - if (GNUNET_OK != database_setup (&plugin)) - { - database_shutdown (&plugin); - return NULL; - } - api = GNUNET_new (struct GNUNET_PSYCSTORE_PluginFunctions); - api->cls = &plugin; - api->membership_store = &mysql_membership_store; - api->membership_test = &membership_test; - api->fragment_store = &fragment_store; - api->message_add_flags = &message_add_flags; - api->fragment_get = &fragment_get; - api->fragment_get_latest = &fragment_get_latest; - api->message_get = &message_get; - api->message_get_latest = &message_get_latest; - api->message_get_fragment = &message_get_fragment; - api->counters_message_get = &counters_message_get; - api->counters_state_get = &counters_state_get; - api->state_modify_begin = &state_modify_begin; - api->state_modify_op = &state_modify_op; - api->state_modify_end = &state_modify_end; - api->state_sync_begin = &state_sync_begin; - api->state_sync_assign = &state_sync_assign; - api->state_sync_end = &state_sync_end; - api->state_reset = &state_reset; - api->state_update_signed = &state_update_signed; - api->state_get = &state_get; - api->state_get_prefix = &state_get_prefix; - api->state_get_signed = &state_get_signed; - - LOG (GNUNET_ERROR_TYPE_INFO, _("Mysql database running\n")); - return api; -} - - -/** - * Exit point from the plugin. - * - * @param cls The plugin context (as returned by "init") - * @return Always NULL - */ -void * -libgnunet_plugin_psycstore_mysql_done (void *cls) -{ - struct GNUNET_PSYCSTORE_PluginFunctions *api = cls; - struct Plugin *plugin = api->cls; - - database_shutdown (plugin); - plugin->cfg = NULL; - GNUNET_free (api); - LOG (GNUNET_ERROR_TYPE_DEBUG, "Mysql plugin is finished\n"); - return NULL; -} - -/* end of plugin_psycstore_mysql.c */ diff --git a/src/psycstore/plugin_psycstore_postgres.c b/src/psycstore/plugin_psycstore_postgres.c deleted file mode 100644 index 33c9960b2..000000000 --- a/src/psycstore/plugin_psycstore_postgres.c +++ /dev/null @@ -1,1530 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2016 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file psycstore/plugin_psycstore_postgres.c - * @brief PostgresQL-based psycstore backend - * @author Daniel Golle - * @author Gabor X Toth - * @author Christian Grothoff - * @author Christophe Genevey - * @author Jeffrey Burdges - */ - -#include "platform.h" -#include "gnunet_psycstore_plugin.h" -#include "gnunet_psycstore_service.h" -#include "gnunet_multicast_service.h" -#include "gnunet_crypto_lib.h" -#include "gnunet_psyc_util_lib.h" -#include "psycstore.h" -#include "gnunet_pq_lib.h" - -/** - * After how many ms "busy" should a DB operation fail for good? A - * low value makes sure that we are more responsive to requests - * (especially PUTs). A high value guarantees a higher success rate - * (SELECTs in iterate can take several seconds despite LIMIT=1). - * - * The default value of 1s should ensure that users do not experience - * huge latencies while at the same time allowing operations to - * succeed with reasonable probability. - */ -#define BUSY_TIMEOUT_MS 1000 - -#define DEBUG_PSYCSTORE GNUNET_EXTRA_LOGGING - -#define LOG(kind,...) GNUNET_log_from (kind, "psycstore-postgres", __VA_ARGS__) - -enum Transactions { - TRANSACTION_NONE = 0, - TRANSACTION_STATE_MODIFY, - TRANSACTION_STATE_SYNC, -}; - -/** - * Context for all functions in this plugin. - */ -struct Plugin -{ - - const struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * Native Postgres database handle. - */ - PGconn *dbh; - - enum Transactions transaction; - - void *cls; -}; - - -/** - * Initialize the database connections and associated - * data structures (create tables and indices - * as needed as well). - * - * @param plugin the plugin context (state for this module) - * @return #GNUNET_OK on success - */ -static int -database_setup (struct Plugin *plugin) -{ - struct GNUNET_PQ_ExecuteStatement es[] = { - GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS channels (\n" - " id SERIAL,\n" - " pub_key BYTEA NOT NULL CHECK (LENGTH(pub_key)=32),\n" - " max_state_message_id BIGINT,\n" - " state_hash_message_id BIGINT,\n" - " PRIMARY KEY(id)\n" - ")" - "WITH OIDS"), - GNUNET_PQ_make_execute ("CREATE UNIQUE INDEX IF NOT EXISTS channel_pub_key_idx \n" - " ON channels (pub_key)"), - GNUNET_PQ_make_execute ("CREATE OR REPLACE FUNCTION get_chan_id(BYTEA) RETURNS INTEGER AS \n" - " 'SELECT id FROM channels WHERE pub_key=$1;' LANGUAGE SQL STABLE \n" - "RETURNS NULL ON NULL INPUT"), - GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS slaves (\n" - " id SERIAL,\n" - " pub_key BYTEA NOT NULL CHECK (LENGTH(pub_key)=32),\n" - " PRIMARY KEY(id)\n" - ")" - "WITH OIDS"), - GNUNET_PQ_make_execute ("CREATE UNIQUE INDEX IF NOT EXISTS slaves_pub_key_idx \n" - " ON slaves (pub_key)"), - GNUNET_PQ_make_execute ("CREATE OR REPLACE FUNCTION get_slave_id(BYTEA) RETURNS INTEGER AS \n" - " 'SELECT id FROM slaves WHERE pub_key=$1;' LANGUAGE SQL STABLE \n" - "RETURNS NULL ON NULL INPUT"), - GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS membership (\n" - " channel_id BIGINT NOT NULL REFERENCES channels(id),\n" - " slave_id BIGINT NOT NULL REFERENCES slaves(id),\n" - " did_join INT NOT NULL,\n" - " announced_at BIGINT NOT NULL,\n" - " effective_since BIGINT NOT NULL,\n" - " group_generation BIGINT NOT NULL\n" - ")" - "WITH OIDS"), - GNUNET_PQ_make_execute ("CREATE INDEX IF NOT EXISTS idx_membership_channel_id_slave_id " - "ON membership (channel_id, slave_id)"), - /** @todo messages table: add method_name column */ - GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS messages (\n" - " channel_id BIGINT NOT NULL REFERENCES channels(id),\n" - " hop_counter INT NOT NULL,\n" - " signature BYTEA CHECK (LENGTH(signature)=64),\n" - " purpose BYTEA CHECK (LENGTH(purpose)=8),\n" - " fragment_id BIGINT NOT NULL,\n" - " fragment_offset BIGINT NOT NULL,\n" - " message_id BIGINT NOT NULL,\n" - " group_generation BIGINT NOT NULL,\n" - " multicast_flags INT NOT NULL,\n" - " psycstore_flags INT NOT NULL,\n" - " data BYTEA,\n" - " PRIMARY KEY (channel_id, fragment_id),\n" - " UNIQUE (channel_id, message_id, fragment_offset)\n" - ")" - "WITH OIDS"), - GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS state (\n" - " channel_id BIGINT NOT NULL REFERENCES channels(id),\n" - " name TEXT NOT NULL,\n" - " value_current BYTEA,\n" - " value_signed BYTEA,\n" - " PRIMARY KEY (channel_id, name)\n" - ")" - "WITH OIDS"), - GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS state_sync (\n" - " channel_id BIGINT NOT NULL REFERENCES channels(id),\n" - " name TEXT NOT NULL,\n" - " value BYTEA,\n" - " PRIMARY KEY (channel_id, name)\n" - ")" - "WITH OIDS"), - GNUNET_PQ_EXECUTE_STATEMENT_END - }; - - /* Open database and precompile statements */ - plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg, - "psycstore-postgres"); - if (NULL == plugin->dbh) - return GNUNET_SYSERR; - if (GNUNET_OK != - GNUNET_PQ_exec_statements (plugin->dbh, - es)) - { - PQfinish (plugin->dbh); - plugin->dbh = NULL; - return GNUNET_SYSERR; - } - - /* Prepare statements */ - { - struct GNUNET_PQ_PreparedStatement ps[] = { - GNUNET_PQ_make_prepare ("transaction_begin", - "BEGIN", 0), - GNUNET_PQ_make_prepare ("transaction_commit", - "COMMIT", 0), - GNUNET_PQ_make_prepare ("transaction_rollback", - "ROLLBACK", 0), - GNUNET_PQ_make_prepare ("insert_channel_key", - "INSERT INTO channels (pub_key) VALUES ($1)" - " ON CONFLICT DO NOTHING", 1), - GNUNET_PQ_make_prepare ("insert_slave_key", - "INSERT INTO slaves (pub_key) VALUES ($1)" - " ON CONFLICT DO NOTHING", 1), - GNUNET_PQ_make_prepare ("insert_membership", - "INSERT INTO membership\n" - " (channel_id, slave_id, did_join, announced_at,\n" - " effective_since, group_generation)\n" - "VALUES (get_chan_id($1),\n" - " get_slave_id($2),\n" - " $3, $4, $5, $6)", 6), - GNUNET_PQ_make_prepare ("select_membership", - "SELECT did_join FROM membership\n" - "WHERE channel_id = get_chan_id($1)\n" - " AND slave_id = get_slave_id($2)\n" - " AND effective_since <= $3 AND did_join = 1\n" - "ORDER BY announced_at DESC LIMIT 1", 3), - GNUNET_PQ_make_prepare ("insert_fragment", - "INSERT INTO messages\n" - " (channel_id, hop_counter, signature, purpose,\n" - " fragment_id, fragment_offset, message_id,\n" - " group_generation, multicast_flags, psycstore_flags, data)\n" - "VALUES (get_chan_id($1),\n" - " $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)" - "ON CONFLICT DO NOTHING", 11), - GNUNET_PQ_make_prepare ("update_message_flags", - "UPDATE messages\n" - "SET psycstore_flags = psycstore_flags | $1\n" - "WHERE channel_id = get_chan_id($2) \n" - " AND message_id = $3 AND fragment_offset = 0", 3), - GNUNET_PQ_make_prepare ("select_fragments", - "SELECT hop_counter, signature, purpose, fragment_id,\n" - " fragment_offset, message_id, group_generation,\n" - " multicast_flags, psycstore_flags, data\n" - "FROM messages\n" - "WHERE channel_id = get_chan_id($1) \n" - " AND $2 <= fragment_id AND fragment_id <= $3", 3), - /** @todo select_messages: add method_prefix filter */ - GNUNET_PQ_make_prepare ("select_messages", - "SELECT hop_counter, signature, purpose, fragment_id,\n" - " fragment_offset, message_id, group_generation,\n" - " multicast_flags, psycstore_flags, data\n" - "FROM messages\n" - "WHERE channel_id = get_chan_id($1) \n" - " AND $2 <= message_id AND message_id <= $3\n" - "LIMIT $4;", 4), - /** @todo select_latest_messages: add method_prefix filter */ - GNUNET_PQ_make_prepare ("select_latest_fragments", - "SELECT rev.hop_counter AS hop_counter,\n" - " rev.signature AS signature,\n" - " rev.purpose AS purpose,\n" - " rev.fragment_id AS fragment_id,\n" - " rev.fragment_offset AS fragment_offset,\n" - " rev.message_id AS message_id,\n" - " rev.group_generation AS group_generation,\n" - " rev.multicast_flags AS multicast_flags,\n" - " rev.psycstore_flags AS psycstore_flags,\n" - " rev.data AS data\n" - " FROM\n" - " (SELECT hop_counter, signature, purpose, fragment_id,\n" - " fragment_offset, message_id, group_generation,\n" - " multicast_flags, psycstore_flags, data \n" - " FROM messages\n" - " WHERE channel_id = get_chan_id($1) \n" - " ORDER BY fragment_id DESC\n" - " LIMIT $2) AS rev\n" - " ORDER BY rev.fragment_id;", 2), - GNUNET_PQ_make_prepare ("select_latest_messages", - "SELECT hop_counter, signature, purpose, fragment_id,\n" - " fragment_offset, message_id, group_generation,\n" - " multicast_flags, psycstore_flags, data\n" - "FROM messages\n" - "WHERE channel_id = get_chan_id($1)\n" - " AND message_id IN\n" - " (SELECT message_id\n" - " FROM messages\n" - " WHERE channel_id = get_chan_id($2) \n" - " GROUP BY message_id\n" - " ORDER BY message_id\n" - " DESC LIMIT $3)\n" - "ORDER BY fragment_id", 3), - GNUNET_PQ_make_prepare ("select_message_fragment", - "SELECT hop_counter, signature, purpose, fragment_id,\n" - " fragment_offset, message_id, group_generation,\n" - " multicast_flags, psycstore_flags, data\n" - "FROM messages\n" - "WHERE channel_id = get_chan_id($1) \n" - " AND message_id = $2 AND fragment_offset = $3", 3), - GNUNET_PQ_make_prepare ("select_counters_message", - "SELECT fragment_id, message_id, group_generation\n" - "FROM messages\n" - "WHERE channel_id = get_chan_id($1)\n" - "ORDER BY fragment_id DESC LIMIT 1", 1), - GNUNET_PQ_make_prepare ("select_counters_state", - "SELECT max_state_message_id\n" - "FROM channels\n" - "WHERE pub_key = $1 AND max_state_message_id IS NOT NULL", 1), - GNUNET_PQ_make_prepare ("update_max_state_message_id", - "UPDATE channels\n" - "SET max_state_message_id = $1\n" - "WHERE pub_key = $2", 2), - - GNUNET_PQ_make_prepare ("update_state_hash_message_id", - "UPDATE channels\n" - "SET state_hash_message_id = $1\n" - "WHERE pub_key = $2", 2), - GNUNET_PQ_make_prepare ("insert_state_current", - "INSERT INTO state\n" - " (channel_id, name, value_current, value_signed)\n" - "SELECT new.channel_id, new.name,\n" - " new.value_current, old.value_signed\n" - "FROM (SELECT get_chan_id($1) AS channel_id,\n" - " $2::TEXT AS name, $3::BYTEA AS value_current) AS new\n" - "LEFT JOIN (SELECT channel_id, name, value_signed\n" - " FROM state) AS old\n" - "ON new.channel_id = old.channel_id AND new.name = old.name\n" - "ON CONFLICT (channel_id, name)\n" - " DO UPDATE SET value_current = EXCLUDED.value_current,\n" - " value_signed = EXCLUDED.value_signed", 3), - GNUNET_PQ_make_prepare ("delete_state_empty", - "DELETE FROM state\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = $1)\n" - " AND (value_current IS NULL OR length(value_current) = 0)\n" - " AND (value_signed IS NULL OR length(value_signed) = 0)", 1), - GNUNET_PQ_make_prepare ("update_state_signed", - "UPDATE state\n" - "SET value_signed = value_current\n" - "WHERE channel_id = get_chan_id($1) ", 1), - GNUNET_PQ_make_prepare ("delete_state", - "DELETE FROM state\n" - "WHERE channel_id = get_chan_id($1) ", 1), - GNUNET_PQ_make_prepare ("insert_state_sync", - "INSERT INTO state_sync (channel_id, name, value)\n" - "VALUES (get_chan_id($1), $2, $3)", 3), - GNUNET_PQ_make_prepare ("insert_state_from_sync", - "INSERT INTO state\n" - " (channel_id, name, value_current, value_signed)\n" - "SELECT channel_id, name, value, value\n" - "FROM state_sync\n" - "WHERE channel_id = get_chan_id($1)", 1), - GNUNET_PQ_make_prepare ("delete_state_sync", - "DELETE FROM state_sync\n" - "WHERE channel_id = get_chan_id($1)", 1), - GNUNET_PQ_make_prepare ("select_state_one", - "SELECT value_current\n" - "FROM state\n" - "WHERE channel_id = get_chan_id($1)\n" - " AND name = $2", 2), - GNUNET_PQ_make_prepare ("select_state_prefix", - "SELECT name, value_current\n" - "FROM state\n" - "WHERE channel_id = get_chan_id($1)\n" - " AND (name = $2 OR substr(name, 1, $3) = $4)", 4), - GNUNET_PQ_make_prepare ("select_state_signed", - "SELECT name, value_signed\n" - "FROM state\n" - "WHERE channel_id = get_chan_id($1)\n" - " AND value_signed IS NOT NULL", 1), - GNUNET_PQ_PREPARED_STATEMENT_END - }; - - if (GNUNET_OK != - GNUNET_PQ_prepare_statements (plugin->dbh, - ps)) - { - PQfinish (plugin->dbh); - plugin->dbh = NULL; - return GNUNET_SYSERR; - } - } - - return GNUNET_OK; -} - - -/** - * Shutdown database connection and associate data - * structures. - * @param plugin the plugin context (state for this module) - */ -static void -database_shutdown (struct Plugin *plugin) -{ - PQfinish (plugin->dbh); - plugin->dbh = NULL; -} - - -/** - * Execute a prepared statement with a @a channel_key argument. - * - * @param plugin Plugin handle. - * @param stmt Statement to execute. - * @param channel_key Public key of the channel. - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -exec_channel (struct Plugin *plugin, const char *stmt, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) -{ - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (channel_key), - GNUNET_PQ_query_param_end - }; - - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != - GNUNET_PQ_eval_prepared_non_select (plugin->dbh, stmt, params)) - return GNUNET_SYSERR; - - return GNUNET_OK; -} - - -/** - * Begin a transaction. - */ -static int -transaction_begin (struct Plugin *plugin, enum Transactions transaction) -{ - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_end - }; - - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != - GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "transaction_begin", params)) - return GNUNET_SYSERR; - - plugin->transaction = transaction; - return GNUNET_OK; -} - - -/** - * Commit current transaction. - */ -static int -transaction_commit (struct Plugin *plugin) -{ - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_end - }; - - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != - GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "transaction_commit", params)) - return GNUNET_SYSERR; - - plugin->transaction = TRANSACTION_NONE; - return GNUNET_OK; -} - - -/** - * Roll back current transaction. - */ -static int -transaction_rollback (struct Plugin *plugin) -{ - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_end - }; - - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != - GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "transaction_rollback", params)) - return GNUNET_SYSERR; - - plugin->transaction = TRANSACTION_NONE; - return GNUNET_OK; -} - - -static int -channel_key_store (struct Plugin *plugin, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) -{ - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (channel_key), - GNUNET_PQ_query_param_end - }; - - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != - GNUNET_PQ_eval_prepared_non_select (plugin->dbh, - "insert_channel_key", - params)) - return GNUNET_SYSERR; - - return GNUNET_OK; -} - - -static int -slave_key_store (struct Plugin *plugin, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key) -{ - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (slave_key), - GNUNET_PQ_query_param_end - }; - - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != - GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "insert_slave_key", params)) - return GNUNET_SYSERR; - - return GNUNET_OK; -} - - -/** - * Store join/leave events for a PSYC channel in order to be able to answer - * membership test queries later. - * - * @see GNUNET_PSYCSTORE_membership_store() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -postgres_membership_store (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - int did_join, - uint64_t announced_at, - uint64_t effective_since, - uint64_t group_generation) -{ - struct Plugin *plugin = cls; - uint32_t idid_join = (uint32_t) did_join; - - GNUNET_assert (TRANSACTION_NONE == plugin->transaction); - - if ( (announced_at > INT64_MAX) || - (effective_since > INT64_MAX) || - (group_generation > INT64_MAX) ) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - - if ( (GNUNET_OK != - channel_key_store (plugin, channel_key)) || - (GNUNET_OK != - slave_key_store (plugin, slave_key)) ) - return GNUNET_SYSERR; - - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (channel_key), - GNUNET_PQ_query_param_auto_from_type (slave_key), - GNUNET_PQ_query_param_uint32 (&idid_join), - GNUNET_PQ_query_param_uint64 (&announced_at), - GNUNET_PQ_query_param_uint64 (&effective_since), - GNUNET_PQ_query_param_uint64 (&group_generation), - GNUNET_PQ_query_param_end - }; - - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != - GNUNET_PQ_eval_prepared_non_select (plugin->dbh, - "insert_membership", - params)) - return GNUNET_SYSERR; - - return GNUNET_OK; -} - -/** - * Test if a member was admitted to the channel at the given message ID. - * - * @see GNUNET_PSYCSTORE_membership_test() - * - * @return #GNUNET_YES if the member was admitted, #GNUNET_NO if not, - * #GNUNET_SYSERR if there was en error. - */ -static int -membership_test (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - uint64_t message_id) -{ - struct Plugin *plugin = cls; - - uint32_t did_join = 0; - - struct GNUNET_PQ_QueryParam params_select[] = { - GNUNET_PQ_query_param_auto_from_type (channel_key), - GNUNET_PQ_query_param_auto_from_type (slave_key), - GNUNET_PQ_query_param_uint64 (&message_id), - GNUNET_PQ_query_param_end - }; - - struct GNUNET_PQ_ResultSpec results_select[] = { - GNUNET_PQ_result_spec_uint32 ("did_join", &did_join), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != - GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, "select_membership", - params_select, results_select)) - return GNUNET_SYSERR; - - return GNUNET_OK; -} - -/** - * Store a message fragment sent to a channel. - * - * @see GNUNET_PSYCSTORE_fragment_store() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -fragment_store (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_MULTICAST_MessageHeader *msg, - uint32_t psycstore_flags) -{ - struct Plugin *plugin = cls; - - GNUNET_assert (TRANSACTION_NONE == plugin->transaction); - - uint64_t fragment_id = GNUNET_ntohll (msg->fragment_id); - - uint64_t fragment_offset = GNUNET_ntohll (msg->fragment_offset); - uint64_t message_id = GNUNET_ntohll (msg->message_id); - uint64_t group_generation = GNUNET_ntohll (msg->group_generation); - - uint32_t hop_counter = ntohl(msg->hop_counter); - uint32_t flags = ntohl(msg->flags); - - if (fragment_id > INT64_MAX || fragment_offset > INT64_MAX || - message_id > INT64_MAX || group_generation > INT64_MAX) - { - LOG(GNUNET_ERROR_TYPE_ERROR, - "Tried to store fragment with a field > INT64_MAX: " - "%lu, %lu, %lu, %lu\n", fragment_id, fragment_offset, - message_id, group_generation); - GNUNET_break (0); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != channel_key_store (plugin, channel_key)) - return GNUNET_SYSERR; - - struct GNUNET_PQ_QueryParam params_insert[] = { - GNUNET_PQ_query_param_auto_from_type (channel_key), - GNUNET_PQ_query_param_uint32 (&hop_counter), - GNUNET_PQ_query_param_auto_from_type (&msg->signature), - GNUNET_PQ_query_param_auto_from_type (&msg->purpose), - GNUNET_PQ_query_param_uint64 (&fragment_id), - GNUNET_PQ_query_param_uint64 (&fragment_offset), - GNUNET_PQ_query_param_uint64 (&message_id), - GNUNET_PQ_query_param_uint64 (&group_generation), - GNUNET_PQ_query_param_uint32 (&flags), - GNUNET_PQ_query_param_uint32 (&psycstore_flags), - GNUNET_PQ_query_param_fixed_size (&msg[1], ntohs (msg->header.size) - sizeof (*msg)), - GNUNET_PQ_query_param_end - }; - - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != - GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "insert_fragment", params_insert)) - return GNUNET_SYSERR; - - return GNUNET_OK; -} - -/** - * Set additional flags for a given message. - * - * They are OR'd with any existing flags set. - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -message_add_flags (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id, - uint32_t psycstore_flags) -{ - struct Plugin *plugin = cls; - - struct GNUNET_PQ_QueryParam params_update[] = { - GNUNET_PQ_query_param_uint32 (&psycstore_flags), - GNUNET_PQ_query_param_auto_from_type (channel_key), - GNUNET_PQ_query_param_uint64 (&message_id), - GNUNET_PQ_query_param_end - }; - - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != - GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "update_message_flags", params_update)) - return GNUNET_SYSERR; - - return GNUNET_OK; -} - - -/** - * Closure for #fragment_rows. - */ -struct FragmentRowsContext { - GNUNET_PSYCSTORE_FragmentCallback cb; - void *cb_cls; - - uint64_t *returned_fragments; - - /* I preserved this but I do not see the point since - * it cannot stop the loop early and gets overwritten ?? */ - int ret; -}; - - -/** - * Callback that retrieves the results of a SELECT statement - * reading form the messages table. - * - * Only passed to GNUNET_PQ_eval_prepared_multi_select and - * has type GNUNET_PQ_PostgresResultHandler. - * - * @param cls closure - * @param result the postgres result - * @param num_result the number of results in @a result - */ -void fragment_rows (void *cls, - PGresult *res, - unsigned int num_results) -{ - struct FragmentRowsContext *c = cls; - - for (unsigned int i=0;iheader.size = htons (sizeof (*mp) + buf_size); - mp->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE); - mp->hop_counter = htonl (hop_counter); - GNUNET_memcpy (&mp->signature, - signature, signature_size); - GNUNET_memcpy (&mp->purpose, - purpose, purpose_size); - mp->fragment_id = GNUNET_htonll (fragment_id); - mp->fragment_offset = GNUNET_htonll (fragment_offset); - mp->message_id = GNUNET_htonll (message_id); - mp->group_generation = GNUNET_htonll (group_generation); - mp->flags = htonl(msg_flags); - - GNUNET_memcpy (&mp[1], - buf, buf_size); - GNUNET_PQ_cleanup_result(results); - c->ret = c->cb (c->cb_cls, mp, (enum GNUNET_PSYCSTORE_MessageFlags) flags); - if (NULL != c->returned_fragments) - (*c->returned_fragments)++; - } -} - - -static int -fragment_select (struct Plugin *plugin, - const char *stmt, - struct GNUNET_PQ_QueryParam *params, - uint64_t *returned_fragments, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls) -{ - /* Stack based closure */ - struct FragmentRowsContext frc = { - .cb = cb, - .cb_cls = cb_cls, - .returned_fragments = returned_fragments, - .ret = GNUNET_SYSERR - }; - - if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh, - stmt, params, - &fragment_rows, &frc)) - return GNUNET_SYSERR; - return frc.ret; /* GNUNET_OK ?? */ -} - -/** - * Retrieve a message fragment range by fragment ID. - * - * @see GNUNET_PSYCSTORE_fragment_get() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -fragment_get (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t first_fragment_id, - uint64_t last_fragment_id, - uint64_t *returned_fragments, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls) -{ - struct Plugin *plugin = cls; - struct GNUNET_PQ_QueryParam params_select[] = { - GNUNET_PQ_query_param_auto_from_type (channel_key), - GNUNET_PQ_query_param_uint64 (&first_fragment_id), - GNUNET_PQ_query_param_uint64 (&last_fragment_id), - GNUNET_PQ_query_param_end - }; - - *returned_fragments = 0; - return fragment_select (plugin, - "select_fragments", - params_select, - returned_fragments, - cb, cb_cls); -} - - -/** - * Retrieve a message fragment range by fragment ID. - * - * @see GNUNET_PSYCSTORE_fragment_get_latest() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -fragment_get_latest (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t fragment_limit, - uint64_t *returned_fragments, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls) -{ - struct Plugin *plugin = cls; - - *returned_fragments = 0; - - struct GNUNET_PQ_QueryParam params_select[] = { - GNUNET_PQ_query_param_auto_from_type (channel_key), - GNUNET_PQ_query_param_uint64 (&fragment_limit), - GNUNET_PQ_query_param_end - }; - - return fragment_select (plugin, - "select_latest_fragments", - params_select, - returned_fragments, - cb, cb_cls); -} - - -/** - * Retrieve all fragments of a message ID range. - * - * @see GNUNET_PSYCSTORE_message_get() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -message_get (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t first_message_id, - uint64_t last_message_id, - uint64_t fragment_limit, - uint64_t *returned_fragments, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls) -{ - struct Plugin *plugin = cls; - struct GNUNET_PQ_QueryParam params_select[] = { - GNUNET_PQ_query_param_auto_from_type (channel_key), - GNUNET_PQ_query_param_uint64 (&first_message_id), - GNUNET_PQ_query_param_uint64 (&last_message_id), - GNUNET_PQ_query_param_uint64 (&fragment_limit), - GNUNET_PQ_query_param_end - }; - - if (0 == fragment_limit) - fragment_limit = INT64_MAX; - *returned_fragments = 0; - return fragment_select (plugin, - "select_messages", - params_select, - returned_fragments, - cb, cb_cls); -} - - -/** - * Retrieve all fragments of the latest messages. - * - * @see GNUNET_PSYCSTORE_message_get_latest() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -message_get_latest (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_limit, - uint64_t *returned_fragments, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls) -{ - struct Plugin *plugin = cls; - struct GNUNET_PQ_QueryParam params_select[] = { - GNUNET_PQ_query_param_auto_from_type (channel_key), - GNUNET_PQ_query_param_auto_from_type (channel_key), - GNUNET_PQ_query_param_uint64 (&message_limit), - GNUNET_PQ_query_param_end - }; - - *returned_fragments = 0; - return fragment_select (plugin, - "select_latest_messages", - params_select, - returned_fragments, - cb, cb_cls); -} - - -/** - * Retrieve a fragment of message specified by its message ID and fragment - * offset. - * - * @see GNUNET_PSYCSTORE_message_get_fragment() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -message_get_fragment (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id, - uint64_t fragment_offset, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls) -{ - struct Plugin *plugin = cls; - const char *stmt = "select_message_fragment"; - - struct GNUNET_PQ_QueryParam params_select[] = { - GNUNET_PQ_query_param_auto_from_type (channel_key), - GNUNET_PQ_query_param_uint64 (&message_id), - GNUNET_PQ_query_param_uint64 (&fragment_offset), - GNUNET_PQ_query_param_end - }; - - /* Stack based closure */ - struct FragmentRowsContext frc = { - .cb = cb, - .cb_cls = cb_cls, - .returned_fragments = NULL, - .ret = GNUNET_SYSERR - }; - - if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh, - stmt, params_select, - &fragment_rows, &frc)) - return GNUNET_SYSERR; - return frc.ret; /* GNUNET_OK ?? */ -} - -/** - * Retrieve the max. values of message counters for a channel. - * - * @see GNUNET_PSYCSTORE_counters_get() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -counters_message_get (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t *max_fragment_id, - uint64_t *max_message_id, - uint64_t *max_group_generation) -{ - struct Plugin *plugin = cls; - - const char *stmt = "select_counters_message"; - - struct GNUNET_PQ_QueryParam params_select[] = { - GNUNET_PQ_query_param_auto_from_type (channel_key), - GNUNET_PQ_query_param_end - }; - - struct GNUNET_PQ_ResultSpec results_select[] = { - GNUNET_PQ_result_spec_uint64 ("fragment_id", max_fragment_id), - GNUNET_PQ_result_spec_uint64 ("message_id", max_message_id), - GNUNET_PQ_result_spec_uint64 ("group_generation", max_group_generation), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != - GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, stmt, - params_select, results_select)) - return GNUNET_SYSERR; - - return GNUNET_OK; -} - -/** - * Retrieve the max. values of state counters for a channel. - * - * @see GNUNET_PSYCSTORE_counters_get() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -counters_state_get (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t *max_state_message_id) -{ - struct Plugin *plugin = cls; - - const char *stmt = "select_counters_state"; - - struct GNUNET_PQ_QueryParam params_select[] = { - GNUNET_PQ_query_param_auto_from_type (channel_key), - GNUNET_PQ_query_param_end - }; - - struct GNUNET_PQ_ResultSpec results_select[] = { - GNUNET_PQ_result_spec_uint64 ("max_state_message_id", max_state_message_id), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != - GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, stmt, - params_select, results_select)) - return GNUNET_SYSERR; - - return GNUNET_OK; -} - - -/** - * Assign a value to a state variable. - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_assign (struct Plugin *plugin, const char *stmt, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const char *name, const void *value, size_t value_size) -{ - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (channel_key), - GNUNET_PQ_query_param_string (name), - GNUNET_PQ_query_param_fixed_size (value, value_size), - GNUNET_PQ_query_param_end - }; - - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != - GNUNET_PQ_eval_prepared_non_select (plugin->dbh, stmt, params)) - return GNUNET_SYSERR; - - return GNUNET_OK; -} - - -static int -update_message_id (struct Plugin *plugin, - const char *stmt, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id) -{ - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_uint64 (&message_id), - GNUNET_PQ_query_param_auto_from_type (channel_key), - GNUNET_PQ_query_param_end - }; - - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != - GNUNET_PQ_eval_prepared_non_select (plugin->dbh, stmt, params)) - return GNUNET_SYSERR; - - return GNUNET_OK; -} - - -/** - * Begin modifying current state. - */ -static int -state_modify_begin (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id, uint64_t state_delta) -{ - struct Plugin *plugin = cls; - - if (state_delta > 0) - { - /** - * We can only apply state modifiers in the current message if modifiers in - * the previous stateful message (message_id - state_delta) were already - * applied. - */ - - uint64_t max_state_message_id = 0; - int ret = counters_state_get (plugin, channel_key, &max_state_message_id); - switch (ret) - { - case GNUNET_OK: - case GNUNET_NO: // no state yet - ret = GNUNET_OK; - break; - - default: - return ret; - } - - if (max_state_message_id < message_id - state_delta) - return GNUNET_NO; /* some stateful messages not yet applied */ - else if (message_id - state_delta < max_state_message_id) - return GNUNET_NO; /* changes already applied */ - } - - if (TRANSACTION_NONE != plugin->transaction) - { - /** @todo FIXME: wait for other transaction to finish */ - return GNUNET_SYSERR; - } - return transaction_begin (plugin, TRANSACTION_STATE_MODIFY); -} - - -/** - * Set the current value of state variable. - * - * @see GNUNET_PSYCSTORE_state_modify() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_modify_op (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - enum GNUNET_PSYC_Operator op, - const char *name, const void *value, size_t value_size) -{ - struct Plugin *plugin = cls; - GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction); - - switch (op) - { - case GNUNET_PSYC_OP_ASSIGN: - return state_assign (plugin, "insert_state_current", - channel_key, name, value, value_size); - - default: /** @todo implement more state operations */ - GNUNET_break (0); - return GNUNET_SYSERR; - } -} - - -/** - * End modifying current state. - */ -static int -state_modify_end (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id) -{ - struct Plugin *plugin = cls; - GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction); - - return - GNUNET_OK == exec_channel (plugin, "delete_state_empty", channel_key) - && GNUNET_OK == update_message_id (plugin, - "update_max_state_message_id", - channel_key, message_id) - && GNUNET_OK == transaction_commit (plugin) - ? GNUNET_OK : GNUNET_SYSERR; -} - - -/** - * Begin state synchronization. - */ -static int -state_sync_begin (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) -{ - struct Plugin *plugin = cls; - return exec_channel (plugin, "delete_state_sync", channel_key); -} - - -/** - * Assign current value of a state variable. - * - * @see GNUNET_PSYCSTORE_state_modify() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_sync_assign (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const char *name, const void *value, size_t value_size) -{ - struct Plugin *plugin = cls; - return state_assign (plugin, "insert_state_sync", - channel_key, name, value, value_size); -} - - -/** - * End modifying current state. - */ -static int -state_sync_end (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t max_state_message_id, - uint64_t state_hash_message_id) -{ - struct Plugin *plugin = cls; - int ret = GNUNET_SYSERR; - - if (TRANSACTION_NONE != plugin->transaction) - { - /** @todo FIXME: wait for other transaction to finish */ - return GNUNET_SYSERR; - } - - GNUNET_OK == transaction_begin (plugin, TRANSACTION_STATE_SYNC) - && GNUNET_OK == exec_channel (plugin, "delete_state", channel_key) - && GNUNET_OK == exec_channel (plugin, "insert_state_from_sync", - channel_key) - && GNUNET_OK == exec_channel (plugin, "delete_state_sync", - channel_key) - && GNUNET_OK == update_message_id (plugin, - "update_state_hash_message_id", - channel_key, state_hash_message_id) - && GNUNET_OK == update_message_id (plugin, - "update_max_state_message_id", - channel_key, max_state_message_id) - && GNUNET_OK == transaction_commit (plugin) - ? ret = GNUNET_OK - : transaction_rollback (plugin); - return ret; -} - - -/** - * Delete the whole state. - * - * @see GNUNET_PSYCSTORE_state_reset() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_reset (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) -{ - struct Plugin *plugin = cls; - return exec_channel (plugin, "delete_state", channel_key); -} - - -/** - * Update signed values of state variables in the state store. - * - * @see GNUNET_PSYCSTORE_state_hash_update() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_update_signed (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) -{ - struct Plugin *plugin = cls; - return exec_channel (plugin, "update_state_signed", channel_key); -} - - -/** - * Retrieve a state variable by name. - * - * @see GNUNET_PSYCSTORE_state_get() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_get (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const char *name, GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls) -{ - struct Plugin *plugin = cls; - - const char *stmt = "select_state_one"; - - struct GNUNET_PQ_QueryParam params_select[] = { - GNUNET_PQ_query_param_auto_from_type (channel_key), - GNUNET_PQ_query_param_string (name), - GNUNET_PQ_query_param_end - }; - - void *value_current = NULL; - size_t value_size = 0; - - struct GNUNET_PQ_ResultSpec results_select[] = { - GNUNET_PQ_result_spec_variable_size ("value_current", &value_current, &value_size), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != - GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, stmt, - params_select, results_select)) - return GNUNET_SYSERR; - - return cb (cb_cls, name, value_current, - value_size); -} - - - -/** - * Closure for #get_state_cb. - */ -struct GetStateContext { - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key; - // const char *name, - GNUNET_PSYCSTORE_StateCallback cb; - void *cb_cls; - - const char *value_id; - - /* I preserved this but I do not see the point since - * it cannot stop the loop early and gets overwritten ?? */ - int ret; -}; - - -/** - * Callback that retrieves the results of a SELECT statement - * reading form the state table. - * - * Only passed to GNUNET_PQ_eval_prepared_multi_select and - * has type GNUNET_PQ_PostgresResultHandler. - * - * @param cls closure - * @param result the postgres result - * @param num_result the number of results in @a result - */ -static void -get_state_cb (void *cls, - PGresult *res, - unsigned int num_results) -{ - struct GetStateContext *c = cls; - - for (unsigned int i=0;ivalue_id, &value, &value_size), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_YES != GNUNET_PQ_extract_result (res, results, i)) - { - GNUNET_PQ_cleanup_result(results); /* previously invoked via PQclear?? */ - break; /* nothing more?? */ - } - - c->ret = c->cb (c->cb_cls, (const char *) name, value, value_size); - GNUNET_PQ_cleanup_result(results); - } -} - -/** - * Retrieve all state variables for a channel with the given prefix. - * - * @see GNUNET_PSYCSTORE_state_get_prefix() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_get_prefix (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const char *name, GNUNET_PSYCSTORE_StateCallback cb, - void *cb_cls) -{ - struct Plugin *plugin = cls; - - const char *stmt = "select_state_prefix"; - - uint32_t name_len = (uint32_t) strlen (name); - - struct GNUNET_PQ_QueryParam params_select[] = { - GNUNET_PQ_query_param_auto_from_type (channel_key), - GNUNET_PQ_query_param_string (name), - GNUNET_PQ_query_param_uint32 (&name_len), - GNUNET_PQ_query_param_string (name), - GNUNET_PQ_query_param_end - }; - - struct GetStateContext gsc = { - .cb = cb, - .cb_cls = cb_cls, - .value_id = "value_current", - .ret = GNUNET_NO - }; - - if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh, - stmt, params_select, - &get_state_cb, &gsc)) - return GNUNET_SYSERR; - return gsc.ret; /* GNUNET_OK ?? */ -} - - -/** - * Retrieve all signed state variables for a channel. - * - * @see GNUNET_PSYCSTORE_state_get_signed() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_get_signed (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls) -{ - struct Plugin *plugin = cls; - - const char *stmt = "select_state_signed"; - - struct GNUNET_PQ_QueryParam params_select[] = { - GNUNET_PQ_query_param_auto_from_type (channel_key), - GNUNET_PQ_query_param_end - }; - - struct GetStateContext gsc = { - .cb = cb, - .cb_cls = cb_cls, - .value_id = "value_signed", - .ret = GNUNET_NO - }; - - if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh, - stmt, params_select, - &get_state_cb, &gsc)) - return GNUNET_SYSERR; - return gsc.ret; /* GNUNET_OK ?? */ -} - - -/** - * Entry point for the plugin. - * - * @param cls The struct GNUNET_CONFIGURATION_Handle. - * @return NULL on error, otherwise the plugin context - */ -void * -libgnunet_plugin_psycstore_postgres_init (void *cls) -{ - static struct Plugin plugin; - const struct GNUNET_CONFIGURATION_Handle *cfg = cls; - struct GNUNET_PSYCSTORE_PluginFunctions *api; - - if (NULL != plugin.cfg) - return NULL; /* can only initialize once! */ - memset (&plugin, 0, sizeof (struct Plugin)); - plugin.cfg = cfg; - if (GNUNET_OK != database_setup (&plugin)) - { - database_shutdown (&plugin); - return NULL; - } - api = GNUNET_new (struct GNUNET_PSYCSTORE_PluginFunctions); - api->cls = &plugin; - api->membership_store = &postgres_membership_store; - api->membership_test = &membership_test; - api->fragment_store = &fragment_store; - api->message_add_flags = &message_add_flags; - api->fragment_get = &fragment_get; - api->fragment_get_latest = &fragment_get_latest; - api->message_get = &message_get; - api->message_get_latest = &message_get_latest; - api->message_get_fragment = &message_get_fragment; - api->counters_message_get = &counters_message_get; - api->counters_state_get = &counters_state_get; - api->state_modify_begin = &state_modify_begin; - api->state_modify_op = &state_modify_op; - api->state_modify_end = &state_modify_end; - api->state_sync_begin = &state_sync_begin; - api->state_sync_assign = &state_sync_assign; - api->state_sync_end = &state_sync_end; - api->state_reset = &state_reset; - api->state_update_signed = &state_update_signed; - api->state_get = &state_get; - api->state_get_prefix = &state_get_prefix; - api->state_get_signed = &state_get_signed; - - LOG (GNUNET_ERROR_TYPE_INFO, _("Postgres database running\n")); - return api; -} - - -/** - * Exit point from the plugin. - * - * @param cls The plugin context (as returned by "init") - * @return Always NULL - */ -void * -libgnunet_plugin_psycstore_postgres_done (void *cls) -{ - struct GNUNET_PSYCSTORE_PluginFunctions *api = cls; - struct Plugin *plugin = api->cls; - - database_shutdown (plugin); - plugin->cfg = NULL; - GNUNET_free (api); - LOG (GNUNET_ERROR_TYPE_DEBUG, "Postgres plugin has finished\n"); - return NULL; -} - -/* end of plugin_psycstore_postgres.c */ diff --git a/src/psycstore/plugin_psycstore_sqlite.c b/src/psycstore/plugin_psycstore_sqlite.c deleted file mode 100644 index 24de38392..000000000 --- a/src/psycstore/plugin_psycstore_sqlite.c +++ /dev/null @@ -1,1948 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file psycstore/plugin_psycstore_sqlite.c - * @brief sqlite-based psycstore backend - * @author Gabor X Toth - * @author Christian Grothoff - */ - -/* - * FIXME: SQLite3 only supports signed 64-bit integers natively, - * thus it can only store 63 bits of the uint64_t's. - */ - -#include "platform.h" -#include "gnunet_psycstore_plugin.h" -#include "gnunet_psycstore_service.h" -#include "gnunet_multicast_service.h" -#include "gnunet_crypto_lib.h" -#include "gnunet_psyc_util_lib.h" -#include "psycstore.h" -#include - -/** - * After how many ms "busy" should a DB operation fail for good? A - * low value makes sure that we are more responsive to requests - * (especially PUTs). A high value guarantees a higher success rate - * (SELECTs in iterate can take several seconds despite LIMIT=1). - * - * The default value of 1s should ensure that users do not experience - * huge latencies while at the same time allowing operations to - * succeed with reasonable probability. - */ -#define BUSY_TIMEOUT_MS 1000 - -#define DEBUG_PSYCSTORE GNUNET_EXTRA_LOGGING - -/** - * Log an error message at log-level 'level' that indicates - * a failure of the command 'cmd' on file 'filename' - * with the message given by strerror(errno). - */ -#define LOG_SQLITE(db, level, cmd) do { GNUNET_log_from (level, "psycstore-sqlite", _("`%s' failed at %s:%d with error: %s (%d)\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh), sqlite3_errcode(db->dbh)); } while(0) - -#define LOG(kind,...) GNUNET_log_from (kind, "psycstore-sqlite", __VA_ARGS__) - -enum Transactions { - TRANSACTION_NONE = 0, - TRANSACTION_STATE_MODIFY, - TRANSACTION_STATE_SYNC, -}; - -/** - * Context for all functions in this plugin. - */ -struct Plugin -{ - - const struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * Database filename. - */ - char *fn; - - /** - * Native SQLite database handle. - */ - sqlite3 *dbh; - - /** - * Current transaction. - */ - enum Transactions transaction; - - sqlite3_stmt *transaction_begin; - - sqlite3_stmt *transaction_commit; - - sqlite3_stmt *transaction_rollback; - - /** - * Precompiled SQL for channel_key_store() - */ - sqlite3_stmt *insert_channel_key; - - /** - * Precompiled SQL for slave_key_store() - */ - sqlite3_stmt *insert_slave_key; - - - /** - * Precompiled SQL for membership_store() - */ - sqlite3_stmt *insert_membership; - - /** - * Precompiled SQL for membership_test() - */ - sqlite3_stmt *select_membership; - - - /** - * Precompiled SQL for fragment_store() - */ - sqlite3_stmt *insert_fragment; - - /** - * Precompiled SQL for message_add_flags() - */ - sqlite3_stmt *update_message_flags; - - /** - * Precompiled SQL for fragment_get() - */ - sqlite3_stmt *select_fragments; - - /** - * Precompiled SQL for fragment_get() - */ - sqlite3_stmt *select_latest_fragments; - - /** - * Precompiled SQL for message_get() - */ - sqlite3_stmt *select_messages; - - /** - * Precompiled SQL for message_get() - */ - sqlite3_stmt *select_latest_messages; - - /** - * Precompiled SQL for message_get_fragment() - */ - sqlite3_stmt *select_message_fragment; - - /** - * Precompiled SQL for counters_get_message() - */ - sqlite3_stmt *select_counters_message; - - /** - * Precompiled SQL for counters_get_state() - */ - sqlite3_stmt *select_counters_state; - - /** - * Precompiled SQL for state_modify_end() - */ - sqlite3_stmt *update_state_hash_message_id; - - /** - * Precompiled SQL for state_sync_end() - */ - sqlite3_stmt *update_max_state_message_id; - - /** - * Precompiled SQL for state_modify_op() - */ - sqlite3_stmt *insert_state_current; - - /** - * Precompiled SQL for state_modify_end() - */ - sqlite3_stmt *delete_state_empty; - - /** - * Precompiled SQL for state_set_signed() - */ - sqlite3_stmt *update_state_signed; - - /** - * Precompiled SQL for state_sync() - */ - sqlite3_stmt *insert_state_sync; - - /** - * Precompiled SQL for state_sync() - */ - sqlite3_stmt *delete_state; - - /** - * Precompiled SQL for state_sync() - */ - sqlite3_stmt *insert_state_from_sync; - - /** - * Precompiled SQL for state_sync() - */ - sqlite3_stmt *delete_state_sync; - - /** - * Precompiled SQL for state_get_signed() - */ - sqlite3_stmt *select_state_signed; - - /** - * Precompiled SQL for state_get() - */ - sqlite3_stmt *select_state_one; - - /** - * Precompiled SQL for state_get_prefix() - */ - sqlite3_stmt *select_state_prefix; - -}; - -#if DEBUG_PSYCSTORE - -static void -sql_trace (void *cls, const char *sql) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "SQL query:\n%s\n", sql); -} - -#endif - -/** - * @brief Prepare a SQL statement - * - * @param dbh handle to the database - * @param sql SQL statement, UTF-8 encoded - * @param stmt set to the prepared statement - * @return 0 on success - */ -static int -sql_prepare (sqlite3 *dbh, const char *sql, sqlite3_stmt **stmt) -{ - char *tail; - int result; - - result = sqlite3_prepare_v2 (dbh, sql, strlen (sql), stmt, - (const char **) &tail); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Prepared `%s' / %p: %d\n", sql, *stmt, result); - if (result != SQLITE_OK) - LOG (GNUNET_ERROR_TYPE_ERROR, - _("Error preparing SQL query: %s\n %s\n"), - sqlite3_errmsg (dbh), sql); - return result; -} - - -/** - * @brief Prepare a SQL statement - * - * @param dbh handle to the database - * @param sql SQL statement, UTF-8 encoded - * @return 0 on success - */ -static int -sql_exec (sqlite3 *dbh, const char *sql) -{ - int result; - - result = sqlite3_exec (dbh, sql, NULL, NULL, NULL); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Executed `%s' / %d\n", sql, result); - if (result != SQLITE_OK) - LOG (GNUNET_ERROR_TYPE_ERROR, - _("Error executing SQL query: %s\n %s\n"), - sqlite3_errmsg (dbh), sql); - return result; -} - - -/** - * Initialize the database connections and associated - * data structures (create tables and indices - * as needed as well). - * - * @param plugin the plugin context (state for this module) - * @return GNUNET_OK on success - */ -static int -database_setup (struct Plugin *plugin) -{ - char *filename; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, "psycstore-sqlite", - "FILENAME", &filename)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "psycstore-sqlite", "FILENAME"); - return GNUNET_SYSERR; - } - if (GNUNET_OK != GNUNET_DISK_file_test (filename)) - { - if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (filename)) - { - GNUNET_break (0); - GNUNET_free (filename); - return GNUNET_SYSERR; - } - } - /* filename should be UTF-8-encoded. If it isn't, it's a bug */ - plugin->fn = filename; - - /* Open database and precompile statements */ - if (SQLITE_OK != sqlite3_open (plugin->fn, &plugin->dbh)) - { - LOG (GNUNET_ERROR_TYPE_ERROR, - _("Unable to initialize SQLite: %s.\n"), - sqlite3_errmsg (plugin->dbh)); - return GNUNET_SYSERR; - } - -#if DEBUG_PSYCSTORE - sqlite3_trace (plugin->dbh, &sql_trace, NULL); -#endif - - sql_exec (plugin->dbh, "PRAGMA temp_store=MEMORY"); - sql_exec (plugin->dbh, "PRAGMA synchronous=NORMAL"); - sql_exec (plugin->dbh, "PRAGMA legacy_file_format=OFF"); - sql_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL"); - sql_exec (plugin->dbh, "PRAGMA encoding=\"UTF-8\""); -#if ! DEBUG_PSYCSTORE - sql_exec (plugin->dbh, "PRAGMA locking_mode=EXCLUSIVE"); -#endif - sql_exec (plugin->dbh, "PRAGMA page_size=4096"); - - sqlite3_busy_timeout (plugin->dbh, BUSY_TIMEOUT_MS); - - /* Create tables */ - - sql_exec (plugin->dbh, - "CREATE TABLE IF NOT EXISTS channels (\n" - " id INTEGER PRIMARY KEY,\n" - " pub_key BLOB(32) UNIQUE,\n" - " max_state_message_id INTEGER,\n" // last applied state message ID - " state_hash_message_id INTEGER\n" // last message ID with a state hash - ");"); - - sql_exec (plugin->dbh, - "CREATE TABLE IF NOT EXISTS slaves (\n" - " id INTEGER PRIMARY KEY,\n" - " pub_key BLOB(32) UNIQUE\n" - ");"); - - sql_exec (plugin->dbh, - "CREATE TABLE IF NOT EXISTS membership (\n" - " channel_id INTEGER NOT NULL REFERENCES channels(id),\n" - " slave_id INTEGER NOT NULL REFERENCES slaves(id),\n" - " did_join INTEGER NOT NULL,\n" - " announced_at INTEGER NOT NULL,\n" - " effective_since INTEGER NOT NULL,\n" - " group_generation INTEGER NOT NULL\n" - ");"); - sql_exec (plugin->dbh, - "CREATE INDEX IF NOT EXISTS idx_membership_channel_id_slave_id " - "ON membership (channel_id, slave_id);"); - - /** @todo messages table: add method_name column */ - sql_exec (plugin->dbh, - "CREATE TABLE IF NOT EXISTS messages (\n" - " channel_id INTEGER NOT NULL REFERENCES channels(id),\n" - " hop_counter INTEGER NOT NULL,\n" - " signature BLOB,\n" - " purpose BLOB,\n" - " fragment_id INTEGER NOT NULL,\n" - " fragment_offset INTEGER NOT NULL,\n" - " message_id INTEGER NOT NULL,\n" - " group_generation INTEGER NOT NULL,\n" - " multicast_flags INTEGER NOT NULL,\n" - " psycstore_flags INTEGER NOT NULL,\n" - " data BLOB,\n" - " PRIMARY KEY (channel_id, fragment_id),\n" - " UNIQUE (channel_id, message_id, fragment_offset)\n" - ");"); - - sql_exec (plugin->dbh, - "CREATE TABLE IF NOT EXISTS state (\n" - " channel_id INTEGER NOT NULL REFERENCES channels(id),\n" - " name TEXT NOT NULL,\n" - " value_current BLOB,\n" - " value_signed BLOB,\n" - " PRIMARY KEY (channel_id, name)\n" - ");"); - - sql_exec (plugin->dbh, - "CREATE TABLE IF NOT EXISTS state_sync (\n" - " channel_id INTEGER NOT NULL REFERENCES channels(id),\n" - " name TEXT NOT NULL,\n" - " value BLOB,\n" - " PRIMARY KEY (channel_id, name)\n" - ");"); - - /* Prepare statements */ - - sql_prepare (plugin->dbh, "BEGIN;", &plugin->transaction_begin); - - sql_prepare (plugin->dbh, "COMMIT;", &plugin->transaction_commit); - - sql_prepare (plugin->dbh, "ROLLBACK;", &plugin->transaction_rollback); - - sql_prepare (plugin->dbh, - "INSERT OR IGNORE INTO channels (pub_key) VALUES (?);", - &plugin->insert_channel_key); - - sql_prepare (plugin->dbh, - "INSERT OR IGNORE INTO slaves (pub_key) VALUES (?);", - &plugin->insert_slave_key); - - sql_prepare (plugin->dbh, - "INSERT INTO membership\n" - " (channel_id, slave_id, did_join, announced_at,\n" - " effective_since, group_generation)\n" - "VALUES ((SELECT id FROM channels WHERE pub_key = ?),\n" - " (SELECT id FROM slaves WHERE pub_key = ?),\n" - " ?, ?, ?, ?);", - &plugin->insert_membership); - - sql_prepare (plugin->dbh, - "SELECT did_join FROM membership\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " AND slave_id = (SELECT id FROM slaves WHERE pub_key = ?)\n" - " AND effective_since <= ? AND did_join = 1\n" - "ORDER BY announced_at DESC LIMIT 1;", - &plugin->select_membership); - - sql_prepare (plugin->dbh, - "INSERT OR IGNORE INTO messages\n" - " (channel_id, hop_counter, signature, purpose,\n" - " fragment_id, fragment_offset, message_id,\n" - " group_generation, multicast_flags, psycstore_flags, data)\n" - "VALUES ((SELECT id FROM channels WHERE pub_key = ?),\n" - " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", - &plugin->insert_fragment); - - sql_prepare (plugin->dbh, - "UPDATE messages\n" - "SET psycstore_flags = psycstore_flags | ?\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " AND message_id = ? AND fragment_offset = 0;", - &plugin->update_message_flags); - - sql_prepare (plugin->dbh, - "SELECT hop_counter, signature, purpose, fragment_id,\n" - " fragment_offset, message_id, group_generation,\n" - " multicast_flags, psycstore_flags, data\n" - "FROM messages\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " AND ? <= fragment_id AND fragment_id <= ?;", - &plugin->select_fragments); - - /** @todo select_messages: add method_prefix filter */ - sql_prepare (plugin->dbh, - "SELECT hop_counter, signature, purpose, fragment_id,\n" - " fragment_offset, message_id, group_generation,\n" - " multicast_flags, psycstore_flags, data\n" - "FROM messages\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " AND ? <= message_id AND message_id <= ?" - "LIMIT ?;", - &plugin->select_messages); - - sql_prepare (plugin->dbh, - "SELECT * FROM\n" - "(SELECT hop_counter, signature, purpose, fragment_id,\n" - " fragment_offset, message_id, group_generation,\n" - " multicast_flags, psycstore_flags, data\n" - " FROM messages\n" - " WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " ORDER BY fragment_id DESC\n" - " LIMIT ?)\n" - "ORDER BY fragment_id;", - &plugin->select_latest_fragments); - - /** @todo select_latest_messages: add method_prefix filter */ - sql_prepare (plugin->dbh, - "SELECT hop_counter, signature, purpose, fragment_id,\n" - " fragment_offset, message_id, group_generation,\n" - " multicast_flags, psycstore_flags, data\n" - "FROM messages\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " AND message_id IN\n" - " (SELECT message_id\n" - " FROM messages\n" - " WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " GROUP BY message_id\n" - " ORDER BY message_id\n" - " DESC LIMIT ?)\n" - "ORDER BY fragment_id;", - &plugin->select_latest_messages); - - sql_prepare (plugin->dbh, - "SELECT hop_counter, signature, purpose, fragment_id,\n" - " fragment_offset, message_id, group_generation,\n" - " multicast_flags, psycstore_flags, data\n" - "FROM messages\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " AND message_id = ? AND fragment_offset = ?;", - &plugin->select_message_fragment); - - sql_prepare (plugin->dbh, - "SELECT fragment_id, message_id, group_generation\n" - "FROM messages\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - "ORDER BY fragment_id DESC LIMIT 1;", - &plugin->select_counters_message); - - sql_prepare (plugin->dbh, - "SELECT max_state_message_id\n" - "FROM channels\n" - "WHERE pub_key = ? AND max_state_message_id IS NOT NULL;", - &plugin->select_counters_state); - - sql_prepare (plugin->dbh, - "UPDATE channels\n" - "SET max_state_message_id = ?\n" - "WHERE pub_key = ?;", - &plugin->update_max_state_message_id); - - sql_prepare (plugin->dbh, - "UPDATE channels\n" - "SET state_hash_message_id = ?\n" - "WHERE pub_key = ?;", - &plugin->update_state_hash_message_id); - - sql_prepare (plugin->dbh, - "INSERT OR REPLACE INTO state\n" - " (channel_id, name, value_current, value_signed)\n" - "SELECT new.channel_id, new.name,\n" - " new.value_current, old.value_signed\n" - "FROM (SELECT (SELECT id FROM channels WHERE pub_key = ?)\n" - " AS channel_id,\n" - " ? AS name, ? AS value_current) AS new\n" - "LEFT JOIN (SELECT channel_id, name, value_signed\n" - " FROM state) AS old\n" - "ON new.channel_id = old.channel_id AND new.name = old.name;", - &plugin->insert_state_current); - - sql_prepare (plugin->dbh, - "DELETE FROM state\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " AND (value_current IS NULL OR length(value_current) = 0)\n" - " AND (value_signed IS NULL OR length(value_signed) = 0);", - &plugin->delete_state_empty); - - sql_prepare (plugin->dbh, - "UPDATE state\n" - "SET value_signed = value_current\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);", - &plugin->update_state_signed); - - sql_prepare (plugin->dbh, - "DELETE FROM state\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);", - &plugin->delete_state); - - sql_prepare (plugin->dbh, - "INSERT INTO state_sync (channel_id, name, value)\n" - "VALUES ((SELECT id FROM channels WHERE pub_key = ?), ?, ?);", - &plugin->insert_state_sync); - - sql_prepare (plugin->dbh, - "INSERT INTO state\n" - " (channel_id, name, value_current, value_signed)\n" - "SELECT channel_id, name, value, value\n" - "FROM state_sync\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);", - &plugin->insert_state_from_sync); - - sql_prepare (plugin->dbh, - "DELETE FROM state_sync\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);", - &plugin->delete_state_sync); - - sql_prepare (plugin->dbh, - "SELECT value_current\n" - "FROM state\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " AND name = ?;", - &plugin->select_state_one); - - sql_prepare (plugin->dbh, - "SELECT name, value_current\n" - "FROM state\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" - " AND (name = ? OR substr(name, 1, ?) = ?);", - &plugin->select_state_prefix); - - sql_prepare (plugin->dbh, - "SELECT name, value_signed\n" - "FROM state\n" - "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)" - " AND value_signed IS NOT NULL;", - &plugin->select_state_signed); - - return GNUNET_OK; -} - - -/** - * Shutdown database connection and associate data - * structures. - * @param plugin the plugin context (state for this module) - */ -static void -database_shutdown (struct Plugin *plugin) -{ - int result; - sqlite3_stmt *stmt; - while (NULL != (stmt = sqlite3_next_stmt (plugin->dbh, NULL))) - { - result = sqlite3_finalize (stmt); - if (SQLITE_OK != result) - LOG (GNUNET_ERROR_TYPE_WARNING, - "Failed to close statement %p: %d\n", stmt, result); - } - if (SQLITE_OK != sqlite3_close (plugin->dbh)) - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close"); - - GNUNET_free_non_null (plugin->fn); -} - -/** - * Execute a prepared statement with a @a channel_key argument. - * - * @param plugin Plugin handle. - * @param stmt Statement to execute. - * @param channel_key Public key of the channel. - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -exec_channel (struct Plugin *plugin, sqlite3_stmt *stmt, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) -{ - if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, - sizeof (*channel_key), SQLITE_STATIC)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind"); - } - else if (SQLITE_DONE != sqlite3_step (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - } - - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - return GNUNET_SYSERR; - } - - return GNUNET_OK; -} - -/** - * Begin a transaction. - */ -static int -transaction_begin (struct Plugin *plugin, enum Transactions transaction) -{ - sqlite3_stmt *stmt = plugin->transaction_begin; - - if (SQLITE_DONE != sqlite3_step (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - } - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - return GNUNET_SYSERR; - } - - plugin->transaction = transaction; - return GNUNET_OK; -} - - -/** - * Commit current transaction. - */ -static int -transaction_commit (struct Plugin *plugin) -{ - sqlite3_stmt *stmt = plugin->transaction_commit; - - if (SQLITE_DONE != sqlite3_step (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - } - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - return GNUNET_SYSERR; - } - - plugin->transaction = TRANSACTION_NONE; - return GNUNET_OK; -} - - -/** - * Roll back current transaction. - */ -static int -transaction_rollback (struct Plugin *plugin) -{ - sqlite3_stmt *stmt = plugin->transaction_rollback; - - if (SQLITE_DONE != sqlite3_step (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - } - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - return GNUNET_SYSERR; - } - plugin->transaction = TRANSACTION_NONE; - return GNUNET_OK; -} - - -static int -channel_key_store (struct Plugin *plugin, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) -{ - sqlite3_stmt *stmt = plugin->insert_channel_key; - - if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, - sizeof (*channel_key), SQLITE_STATIC)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind"); - } - else if (SQLITE_DONE != sqlite3_step (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - } - - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - return GNUNET_SYSERR; - } - - return GNUNET_OK; -} - - -static int -slave_key_store (struct Plugin *plugin, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key) -{ - sqlite3_stmt *stmt = plugin->insert_slave_key; - - if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, slave_key, - sizeof (*slave_key), SQLITE_STATIC)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind"); - } - else if (SQLITE_DONE != sqlite3_step (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - } - - - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - return GNUNET_SYSERR; - } - - return GNUNET_OK; -} - - -/** - * Store join/leave events for a PSYC channel in order to be able to answer - * membership test queries later. - * - * @see GNUNET_PSYCSTORE_membership_store() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -sqlite_membership_store (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - int did_join, - uint64_t announced_at, - uint64_t effective_since, - uint64_t group_generation) -{ - struct Plugin *plugin = cls; - sqlite3_stmt *stmt = plugin->insert_membership; - - GNUNET_assert (TRANSACTION_NONE == plugin->transaction); - - if (announced_at > INT64_MAX || - effective_since > INT64_MAX || - group_generation > INT64_MAX) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != channel_key_store (plugin, channel_key) - || GNUNET_OK != slave_key_store (plugin, slave_key)) - return GNUNET_SYSERR; - - if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, - sizeof (*channel_key), SQLITE_STATIC) - || SQLITE_OK != sqlite3_bind_blob (stmt, 2, slave_key, - sizeof (*slave_key), SQLITE_STATIC) - || SQLITE_OK != sqlite3_bind_int (stmt, 3, did_join) - || SQLITE_OK != sqlite3_bind_int64 (stmt, 4, announced_at) - || SQLITE_OK != sqlite3_bind_int64 (stmt, 5, effective_since) - || SQLITE_OK != sqlite3_bind_int64 (stmt, 6, group_generation)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind"); - } - else if (SQLITE_DONE != sqlite3_step (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - } - - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - return GNUNET_SYSERR; - } - - return GNUNET_OK; -} - -/** - * Test if a member was admitted to the channel at the given message ID. - * - * @see GNUNET_PSYCSTORE_membership_test() - * - * @return #GNUNET_YES if the member was admitted, #GNUNET_NO if not, - * #GNUNET_SYSERR if there was en error. - */ -static int -membership_test (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - uint64_t message_id) -{ - struct Plugin *plugin = cls; - sqlite3_stmt *stmt = plugin->select_membership; - int ret = GNUNET_SYSERR; - - if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, - sizeof (*channel_key), SQLITE_STATIC) - || SQLITE_OK != sqlite3_bind_blob (stmt, 2, slave_key, - sizeof (*slave_key), SQLITE_STATIC) - || SQLITE_OK != sqlite3_bind_int64 (stmt, 3, message_id)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind"); - } - else - { - switch (sqlite3_step (stmt)) - { - case SQLITE_DONE: - ret = GNUNET_NO; - break; - case SQLITE_ROW: - ret = GNUNET_YES; - } - } - - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - } - - return ret; -} - -/** - * Store a message fragment sent to a channel. - * - * @see GNUNET_PSYCSTORE_fragment_store() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -fragment_store (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_MULTICAST_MessageHeader *msg, - uint32_t psycstore_flags) -{ - struct Plugin *plugin = cls; - sqlite3_stmt *stmt = plugin->insert_fragment; - - GNUNET_assert (TRANSACTION_NONE == plugin->transaction); - - uint64_t fragment_id = GNUNET_ntohll (msg->fragment_id); - uint64_t fragment_offset = GNUNET_ntohll (msg->fragment_offset); - uint64_t message_id = GNUNET_ntohll (msg->message_id); - uint64_t group_generation = GNUNET_ntohll (msg->group_generation); - - if (fragment_id > INT64_MAX || fragment_offset > INT64_MAX || - message_id > INT64_MAX || group_generation > INT64_MAX) - { - LOG (GNUNET_ERROR_TYPE_ERROR, - "Tried to store fragment with a field > INT64_MAX: " - "%lu, %lu, %lu, %lu\n", fragment_id, fragment_offset, - message_id, group_generation); - GNUNET_break (0); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != channel_key_store (plugin, channel_key)) - return GNUNET_SYSERR; - - if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, - sizeof (*channel_key), SQLITE_STATIC) - || SQLITE_OK != sqlite3_bind_int64 (stmt, 2, ntohl (msg->hop_counter) ) - || SQLITE_OK != sqlite3_bind_blob (stmt, 3, (const void *) &msg->signature, - sizeof (msg->signature), SQLITE_STATIC) - || SQLITE_OK != sqlite3_bind_blob (stmt, 4, (const void *) &msg->purpose, - sizeof (msg->purpose), SQLITE_STATIC) - || SQLITE_OK != sqlite3_bind_int64 (stmt, 5, fragment_id) - || SQLITE_OK != sqlite3_bind_int64 (stmt, 6, fragment_offset) - || SQLITE_OK != sqlite3_bind_int64 (stmt, 7, message_id) - || SQLITE_OK != sqlite3_bind_int64 (stmt, 8, group_generation) - || SQLITE_OK != sqlite3_bind_int64 (stmt, 9, ntohl (msg->flags)) - || SQLITE_OK != sqlite3_bind_int64 (stmt, 10, psycstore_flags) - || SQLITE_OK != sqlite3_bind_blob (stmt, 11, (const void *) &msg[1], - ntohs (msg->header.size) - - sizeof (*msg), SQLITE_STATIC)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind"); - } - else if (SQLITE_DONE != sqlite3_step (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - } - - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - return GNUNET_SYSERR; - } - - return GNUNET_OK; -} - -/** - * Set additional flags for a given message. - * - * They are OR'd with any existing flags set. - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -message_add_flags (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id, - uint32_t psycstore_flags) -{ - struct Plugin *plugin = cls; - sqlite3_stmt *stmt = plugin->update_message_flags; - int ret = GNUNET_SYSERR; - - if (SQLITE_OK != sqlite3_bind_int64 (stmt, 1, psycstore_flags) - || SQLITE_OK != sqlite3_bind_blob (stmt, 2, channel_key, - sizeof (*channel_key), SQLITE_STATIC) - || SQLITE_OK != sqlite3_bind_int64 (stmt, 3, message_id)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind"); - } - else - { - switch (sqlite3_step (stmt)) - { - case SQLITE_DONE: - ret = sqlite3_total_changes (plugin->dbh) > 0 ? GNUNET_OK : GNUNET_NO; - break; - default: - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - } - } - - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - return GNUNET_SYSERR; - } - - return ret; -} - -static int -fragment_row (sqlite3_stmt *stmt, GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls) -{ - int data_size = sqlite3_column_bytes (stmt, 9); - struct GNUNET_MULTICAST_MessageHeader *msg - = GNUNET_malloc (sizeof (*msg) + data_size); - - msg->header.size = htons (sizeof (*msg) + data_size); - msg->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE); - msg->hop_counter = htonl ((uint32_t) sqlite3_column_int64 (stmt, 0)); - GNUNET_memcpy (&msg->signature, - sqlite3_column_blob (stmt, 1), - sqlite3_column_bytes (stmt, 1)); - GNUNET_memcpy (&msg->purpose, - sqlite3_column_blob (stmt, 2), - sqlite3_column_bytes (stmt, 2)); - msg->fragment_id = GNUNET_htonll (sqlite3_column_int64 (stmt, 3)); - msg->fragment_offset = GNUNET_htonll (sqlite3_column_int64 (stmt, 4)); - msg->message_id = GNUNET_htonll (sqlite3_column_int64 (stmt, 5)); - msg->group_generation = GNUNET_htonll (sqlite3_column_int64 (stmt, 6)); - msg->flags = htonl (sqlite3_column_int64 (stmt, 7)); - GNUNET_memcpy (&msg[1], sqlite3_column_blob (stmt, 9), data_size); - - return cb (cb_cls, (void *) msg, sqlite3_column_int64 (stmt, 8)); -} - - -static int -fragment_select (struct Plugin *plugin, sqlite3_stmt *stmt, - uint64_t *returned_fragments, - GNUNET_PSYCSTORE_FragmentCallback cb, void *cb_cls) -{ - int ret = GNUNET_SYSERR; - int sql_ret; - - do - { - sql_ret = sqlite3_step (stmt); - switch (sql_ret) - { - case SQLITE_DONE: - if (ret != GNUNET_OK) - ret = GNUNET_NO; - break; - case SQLITE_ROW: - ret = fragment_row (stmt, cb, cb_cls); - (*returned_fragments)++; - if (ret != GNUNET_YES) - sql_ret = SQLITE_DONE; - break; - default: - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - } - } - while (sql_ret == SQLITE_ROW); - - return ret; -} - -/** - * Retrieve a message fragment range by fragment ID. - * - * @see GNUNET_PSYCSTORE_fragment_get() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -fragment_get (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t first_fragment_id, - uint64_t last_fragment_id, - uint64_t *returned_fragments, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls) -{ - struct Plugin *plugin = cls; - sqlite3_stmt *stmt = plugin->select_fragments; - int ret = GNUNET_SYSERR; - *returned_fragments = 0; - - if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, - sizeof (*channel_key), - SQLITE_STATIC) - || SQLITE_OK != sqlite3_bind_int64 (stmt, 2, first_fragment_id) - || SQLITE_OK != sqlite3_bind_int64 (stmt, 3, last_fragment_id)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind"); - } - else - { - ret = fragment_select (plugin, stmt, returned_fragments, cb, cb_cls); - } - - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - } - - return ret; -} - - -/** - * Retrieve a message fragment range by fragment ID. - * - * @see GNUNET_PSYCSTORE_fragment_get_latest() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -fragment_get_latest (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t fragment_limit, - uint64_t *returned_fragments, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls) -{ - struct Plugin *plugin = cls; - sqlite3_stmt *stmt = plugin->select_latest_fragments; - int ret = GNUNET_SYSERR; - *returned_fragments = 0; - - if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, - sizeof (*channel_key), - SQLITE_STATIC) - || SQLITE_OK != sqlite3_bind_int64 (stmt, 2, fragment_limit)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind"); - } - else - { - ret = fragment_select (plugin, stmt, returned_fragments, cb, cb_cls); - } - - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - } - - return ret; -} - - -/** - * Retrieve all fragments of a message ID range. - * - * @see GNUNET_PSYCSTORE_message_get() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -message_get (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t first_message_id, - uint64_t last_message_id, - uint64_t fragment_limit, - uint64_t *returned_fragments, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls) -{ - struct Plugin *plugin = cls; - sqlite3_stmt *stmt = plugin->select_messages; - int ret = GNUNET_SYSERR; - *returned_fragments = 0; - - if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, - sizeof (*channel_key), - SQLITE_STATIC) - || SQLITE_OK != sqlite3_bind_int64 (stmt, 2, first_message_id) - || SQLITE_OK != sqlite3_bind_int64 (stmt, 3, last_message_id) - || SQLITE_OK != sqlite3_bind_int64 (stmt, 4, - (0 != fragment_limit) - ? fragment_limit - : INT64_MAX)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind"); - } - else - { - ret = fragment_select (plugin, stmt, returned_fragments, cb, cb_cls); - } - - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - } - - return ret; -} - - -/** - * Retrieve all fragments of the latest messages. - * - * @see GNUNET_PSYCSTORE_message_get_latest() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -message_get_latest (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_limit, - uint64_t *returned_fragments, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls) -{ - struct Plugin *plugin = cls; - sqlite3_stmt *stmt = plugin->select_latest_messages; - int ret = GNUNET_SYSERR; - *returned_fragments = 0; - - if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, - sizeof (*channel_key), - SQLITE_STATIC) - || SQLITE_OK != sqlite3_bind_blob (stmt, 2, channel_key, - sizeof (*channel_key), - SQLITE_STATIC) - || SQLITE_OK != sqlite3_bind_int64 (stmt, 3, message_limit)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind"); - } - else - { - ret = fragment_select (plugin, stmt, returned_fragments, cb, cb_cls); - } - - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - } - - return ret; -} - - -/** - * Retrieve a fragment of message specified by its message ID and fragment - * offset. - * - * @see GNUNET_PSYCSTORE_message_get_fragment() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -message_get_fragment (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id, - uint64_t fragment_offset, - GNUNET_PSYCSTORE_FragmentCallback cb, - void *cb_cls) -{ - struct Plugin *plugin = cls; - sqlite3_stmt *stmt = plugin->select_message_fragment; - int ret = GNUNET_SYSERR; - - if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, - sizeof (*channel_key), - SQLITE_STATIC) - || SQLITE_OK != sqlite3_bind_int64 (stmt, 2, message_id) - || SQLITE_OK != sqlite3_bind_int64 (stmt, 3, fragment_offset)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind"); - } - else - { - switch (sqlite3_step (stmt)) - { - case SQLITE_DONE: - ret = GNUNET_NO; - break; - case SQLITE_ROW: - ret = fragment_row (stmt, cb, cb_cls); - break; - default: - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - } - } - - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - } - - return ret; -} - -/** - * Retrieve the max. values of message counters for a channel. - * - * @see GNUNET_PSYCSTORE_counters_get() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -counters_message_get (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t *max_fragment_id, - uint64_t *max_message_id, - uint64_t *max_group_generation) -{ - struct Plugin *plugin = cls; - sqlite3_stmt *stmt = plugin->select_counters_message; - int ret = GNUNET_SYSERR; - - if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, - sizeof (*channel_key), - SQLITE_STATIC)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind"); - } - else - { - switch (sqlite3_step (stmt)) - { - case SQLITE_DONE: - ret = GNUNET_NO; - break; - case SQLITE_ROW: - *max_fragment_id = sqlite3_column_int64 (stmt, 0); - *max_message_id = sqlite3_column_int64 (stmt, 1); - *max_group_generation = sqlite3_column_int64 (stmt, 2); - ret = GNUNET_OK; - break; - default: - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - } - } - - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - } - - return ret; -} - -/** - * Retrieve the max. values of state counters for a channel. - * - * @see GNUNET_PSYCSTORE_counters_get() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -counters_state_get (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t *max_state_message_id) -{ - struct Plugin *plugin = cls; - sqlite3_stmt *stmt = plugin->select_counters_state; - int ret = GNUNET_SYSERR; - - if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, - sizeof (*channel_key), - SQLITE_STATIC)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind"); - } - else - { - switch (sqlite3_step (stmt)) - { - case SQLITE_DONE: - ret = GNUNET_NO; - break; - case SQLITE_ROW: - *max_state_message_id = sqlite3_column_int64 (stmt, 0); - ret = GNUNET_OK; - break; - default: - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - } - } - - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - } - - return ret; -} - - -/** - * Assign a value to a state variable. - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_assign (struct Plugin *plugin, sqlite3_stmt *stmt, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const char *name, const void *value, size_t value_size) -{ - int ret = GNUNET_SYSERR; - - if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, - sizeof (*channel_key), SQLITE_STATIC) - || SQLITE_OK != sqlite3_bind_text (stmt, 2, name, -1, SQLITE_STATIC) - || SQLITE_OK != sqlite3_bind_blob (stmt, 3, value, value_size, - SQLITE_STATIC)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind"); - } - else - { - switch (sqlite3_step (stmt)) - { - case SQLITE_DONE: - ret = 0 < sqlite3_total_changes (plugin->dbh) ? GNUNET_OK : GNUNET_NO; - break; - default: - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - } - } - - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - return GNUNET_SYSERR; - } - - return ret; -} - - -static int -update_message_id (struct Plugin *plugin, sqlite3_stmt *stmt, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id) -{ - if (SQLITE_OK != sqlite3_bind_int64 (stmt, 1, message_id) - || SQLITE_OK != sqlite3_bind_blob (stmt, 2, channel_key, - sizeof (*channel_key), SQLITE_STATIC)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind"); - } - else if (SQLITE_DONE != sqlite3_step (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - } - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Begin modifying current state. - */ -static int -state_modify_begin (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id, uint64_t state_delta) -{ - struct Plugin *plugin = cls; - - if (state_delta > 0) - { - /** - * We can only apply state modifiers in the current message if modifiers in - * the previous stateful message (message_id - state_delta) were already - * applied. - */ - - uint64_t max_state_message_id = 0; - int ret = counters_state_get (plugin, channel_key, &max_state_message_id); - switch (ret) - { - case GNUNET_OK: - case GNUNET_NO: // no state yet - ret = GNUNET_OK; - break; - default: - return ret; - } - - if (max_state_message_id < message_id - state_delta) - return GNUNET_NO; /* some stateful messages not yet applied */ - else if (message_id - state_delta < max_state_message_id) - return GNUNET_NO; /* changes already applied */ - } - - if (TRANSACTION_NONE != plugin->transaction) - { - /** @todo FIXME: wait for other transaction to finish */ - return GNUNET_SYSERR; - } - return transaction_begin (plugin, TRANSACTION_STATE_MODIFY); -} - - -/** - * Set the current value of state variable. - * - * @see GNUNET_PSYCSTORE_state_modify() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_modify_op (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - enum GNUNET_PSYC_Operator op, - const char *name, const void *value, size_t value_size) -{ - struct Plugin *plugin = cls; - GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction); - - switch (op) - { - case GNUNET_PSYC_OP_ASSIGN: - return state_assign (plugin, plugin->insert_state_current, channel_key, - name, value, value_size); - - default: /** @todo implement more state operations */ - GNUNET_break (0); - return GNUNET_SYSERR; - } -} - - -/** - * End modifying current state. - */ -static int -state_modify_end (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id) -{ - struct Plugin *plugin = cls; - GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction); - - return - GNUNET_OK == exec_channel (plugin, plugin->delete_state_empty, channel_key) - && GNUNET_OK == update_message_id (plugin, - plugin->update_max_state_message_id, - channel_key, message_id) - && GNUNET_OK == transaction_commit (plugin) - ? GNUNET_OK : GNUNET_SYSERR; -} - - -/** - * Begin state synchronization. - */ -static int -state_sync_begin (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) -{ - struct Plugin *plugin = cls; - return exec_channel (plugin, plugin->delete_state_sync, channel_key); -} - - -/** - * Assign current value of a state variable. - * - * @see GNUNET_PSYCSTORE_state_modify() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_sync_assign (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const char *name, const void *value, size_t value_size) -{ - struct Plugin *plugin = cls; - return state_assign (cls, plugin->insert_state_sync, channel_key, - name, value, value_size); -} - - -/** - * End modifying current state. - */ -static int -state_sync_end (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t max_state_message_id, - uint64_t state_hash_message_id) -{ - struct Plugin *plugin = cls; - int ret = GNUNET_SYSERR; - - if (TRANSACTION_NONE != plugin->transaction) - { - /** @todo FIXME: wait for other transaction to finish */ - return GNUNET_SYSERR; - } - - GNUNET_OK == transaction_begin (plugin, TRANSACTION_STATE_SYNC) - && GNUNET_OK == exec_channel (plugin, plugin->delete_state, channel_key) - && GNUNET_OK == exec_channel (plugin, plugin->insert_state_from_sync, - channel_key) - && GNUNET_OK == exec_channel (plugin, plugin->delete_state_sync, - channel_key) - && GNUNET_OK == update_message_id (plugin, - plugin->update_state_hash_message_id, - channel_key, state_hash_message_id) - && GNUNET_OK == update_message_id (plugin, - plugin->update_max_state_message_id, - channel_key, max_state_message_id) - && GNUNET_OK == transaction_commit (plugin) - ? ret = GNUNET_OK - : transaction_rollback (plugin); - return ret; -} - - -/** - * Delete the whole state. - * - * @see GNUNET_PSYCSTORE_state_reset() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_reset (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) -{ - struct Plugin *plugin = cls; - return exec_channel (plugin, plugin->delete_state, channel_key); -} - - -/** - * Update signed values of state variables in the state store. - * - * @see GNUNET_PSYCSTORE_state_hash_update() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_update_signed (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) -{ - struct Plugin *plugin = cls; - return exec_channel (plugin, plugin->update_state_signed, channel_key); -} - - -/** - * Retrieve a state variable by name. - * - * @see GNUNET_PSYCSTORE_state_get() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_get (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const char *name, GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls) -{ - struct Plugin *plugin = cls; - int ret = GNUNET_SYSERR; - - sqlite3_stmt *stmt = plugin->select_state_one; - - if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, - sizeof (*channel_key), - SQLITE_STATIC) - || SQLITE_OK != sqlite3_bind_text (stmt, 2, name, -1, SQLITE_STATIC)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind"); - } - else - { - switch (sqlite3_step (stmt)) - { - case SQLITE_DONE: - ret = GNUNET_NO; - break; - case SQLITE_ROW: - ret = cb (cb_cls, name, sqlite3_column_blob (stmt, 0), - sqlite3_column_bytes (stmt, 0)); - break; - default: - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - } - } - - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - } - - return ret; -} - - -/** - * Retrieve all state variables for a channel with the given prefix. - * - * @see GNUNET_PSYCSTORE_state_get_prefix() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_get_prefix (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const char *name, GNUNET_PSYCSTORE_StateCallback cb, - void *cb_cls) -{ - struct Plugin *plugin = cls; - int ret = GNUNET_SYSERR; - sqlite3_stmt *stmt = plugin->select_state_prefix; - size_t name_len = strlen (name); - - if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, - sizeof (*channel_key), SQLITE_STATIC) - || SQLITE_OK != sqlite3_bind_text (stmt, 2, name, name_len, SQLITE_STATIC) - || SQLITE_OK != sqlite3_bind_int (stmt, 3, name_len) - || SQLITE_OK != sqlite3_bind_text (stmt, 4, name, name_len, SQLITE_STATIC)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind"); - } - else - { - int sql_ret; - do - { - sql_ret = sqlite3_step (stmt); - switch (sql_ret) - { - case SQLITE_DONE: - if (ret != GNUNET_OK) - ret = GNUNET_NO; - break; - case SQLITE_ROW: - ret = cb (cb_cls, (const char *) sqlite3_column_text (stmt, 0), - sqlite3_column_blob (stmt, 1), - sqlite3_column_bytes (stmt, 1)); - if (ret != GNUNET_YES) - sql_ret = SQLITE_DONE; - break; - default: - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - } - } - while (sql_ret == SQLITE_ROW); - } - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - } - return ret; -} - - -/** - * Retrieve all signed state variables for a channel. - * - * @see GNUNET_PSYCSTORE_state_get_signed() - * - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -state_get_signed (void *cls, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls) -{ - struct Plugin *plugin = cls; - int ret = GNUNET_SYSERR; - - sqlite3_stmt *stmt = plugin->select_state_signed; - - if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, - sizeof (*channel_key), SQLITE_STATIC)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind"); - } - else - { - int sql_ret; - do - { - sql_ret = sqlite3_step (stmt); - switch (sql_ret) - { - case SQLITE_DONE: - if (ret != GNUNET_OK) - ret = GNUNET_NO; - break; - case SQLITE_ROW: - ret = cb (cb_cls, (const char *) sqlite3_column_text (stmt, 0), - sqlite3_column_blob (stmt, 1), - sqlite3_column_bytes (stmt, 1)); - if (ret != GNUNET_YES) - sql_ret = SQLITE_DONE; - break; - default: - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - } - } - while (sql_ret == SQLITE_ROW); - } - - if (SQLITE_OK != sqlite3_reset (stmt)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_reset"); - } - - return ret; -} - - -/** - * Entry point for the plugin. - * - * @param cls The struct GNUNET_CONFIGURATION_Handle. - * @return NULL on error, otherwise the plugin context - */ -void * -libgnunet_plugin_psycstore_sqlite_init (void *cls) -{ - static struct Plugin plugin; - const struct GNUNET_CONFIGURATION_Handle *cfg = cls; - struct GNUNET_PSYCSTORE_PluginFunctions *api; - - if (NULL != plugin.cfg) - return NULL; /* can only initialize once! */ - memset (&plugin, 0, sizeof (struct Plugin)); - plugin.cfg = cfg; - if (GNUNET_OK != database_setup (&plugin)) - { - database_shutdown (&plugin); - return NULL; - } - api = GNUNET_new (struct GNUNET_PSYCSTORE_PluginFunctions); - api->cls = &plugin; - api->membership_store = &sqlite_membership_store; - api->membership_test = &membership_test; - api->fragment_store = &fragment_store; - api->message_add_flags = &message_add_flags; - api->fragment_get = &fragment_get; - api->fragment_get_latest = &fragment_get_latest; - api->message_get = &message_get; - api->message_get_latest = &message_get_latest; - api->message_get_fragment = &message_get_fragment; - api->counters_message_get = &counters_message_get; - api->counters_state_get = &counters_state_get; - api->state_modify_begin = &state_modify_begin; - api->state_modify_op = &state_modify_op; - api->state_modify_end = &state_modify_end; - api->state_sync_begin = &state_sync_begin; - api->state_sync_assign = &state_sync_assign; - api->state_sync_end = &state_sync_end; - api->state_reset = &state_reset; - api->state_update_signed = &state_update_signed; - api->state_get = &state_get; - api->state_get_prefix = &state_get_prefix; - api->state_get_signed = &state_get_signed; - - LOG (GNUNET_ERROR_TYPE_INFO, _("SQLite database running\n")); - return api; -} - - -/** - * Exit point from the plugin. - * - * @param cls The plugin context (as returned by "init") - * @return Always NULL - */ -void * -libgnunet_plugin_psycstore_sqlite_done (void *cls) -{ - struct GNUNET_PSYCSTORE_PluginFunctions *api = cls; - struct Plugin *plugin = api->cls; - - database_shutdown (plugin); - plugin->cfg = NULL; - GNUNET_free (api); - LOG (GNUNET_ERROR_TYPE_DEBUG, "SQLite plugin is finished\n"); - return NULL; -} - -/* end of plugin_psycstore_sqlite.c */ diff --git a/src/psycstore/psycstore.conf.in b/src/psycstore/psycstore.conf.in deleted file mode 100644 index 3905db173..000000000 --- a/src/psycstore/psycstore.conf.in +++ /dev/null @@ -1,28 +0,0 @@ -[psycstore] -START_ON_DEMAND = @START_ON_DEMAND@ -BINARY = gnunet-service-psycstore - -UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-psycstore.sock -UNIX_MATCH_UID = YES -UNIX_MATCH_GID = YES - -@UNIXONLY@PORT = 2111 -HOSTNAME = localhost -ACCEPT_FROM = 127.0.0.1; -ACCEPT_FROM6 = ::1; - -DATABASE = sqlite - -[psycstore-sqlite] -FILENAME = $GNUNET_DATA_HOME/psycstore/sqlite.db - -[psycstore-mysql] -DATABASE = gnunet -CONFIG = ~/.my.cnf -# USER = gnunet -# PASSWORD = -# HOST = localhost -# PORT = 3306 - -[psycstore-postgres] -CONFIG = connect_timeout=10; dbname=gnunet diff --git a/src/psycstore/psycstore.h b/src/psycstore/psycstore.h deleted file mode 100644 index 9a1c06aa8..000000000 --- a/src/psycstore/psycstore.h +++ /dev/null @@ -1,520 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file psycstore/psycstore.h - * @brief Common type definitions for the PSYCstore service and API. - * @author Gabor X Toth - */ - -#ifndef GNUNET_PSYCSTORE_H -#define GNUNET_PSYCSTORE_H - -#include "gnunet_common.h" - - -GNUNET_NETWORK_STRUCT_BEGIN - -/** - * Answer from service to client about last operation. - */ -struct OperationResult -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE - */ - struct GNUNET_MessageHeader header; - - uint32_t reserved GNUNET_PACKED; - - /** - * Operation ID. - */ - uint64_t op_id GNUNET_PACKED; - - /**lowed by - * Status code for the operation. - */ - uint64_t result_code GNUNET_PACKED; - - /* followed by 0-terminated error message (on error) */ - -}; - - -/** - * Answer from service to client about master counters. - * - * @see GNUNET_PSYCSTORE_counters_get() - */ -struct CountersResult -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_COUNTERS - */ - struct GNUNET_MessageHeader header; - - /** - * Status code for the operation: - * #GNUNET_OK: success, counter values are returned. - * #GNUNET_NO: no message has been sent to the channel yet. - * #GNUNET_SYSERR: an error occurred. - */ - uint32_t result_code GNUNET_PACKED; - - /** - * Operation ID. - */ - uint64_t op_id GNUNET_PACKED; - - uint64_t max_fragment_id GNUNET_PACKED; - - uint64_t max_message_id GNUNET_PACKED; - - uint64_t max_group_generation GNUNET_PACKED; - - uint64_t max_state_message_id GNUNET_PACKED; -}; - - -/** - * Answer from service to client containing a message fragment. - */ -struct FragmentResult -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE - */ - struct GNUNET_MessageHeader header; - - uint32_t psycstore_flags GNUNET_PACKED; - - /** - * Operation ID. - */ - uint64_t op_id GNUNET_PACKED; - - /* Followed by GNUNET_MULTICAST_MessageHeader */ -}; - - -/** - * Answer from service to client containing a state variable. - */ -struct StateResult -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE - */ - struct GNUNET_MessageHeader header; - - uint16_t name_size GNUNET_PACKED; - - uint16_t reserved GNUNET_PACKED; - - /** - * Operation ID. - */ - uint64_t op_id GNUNET_PACKED; - - /* Followed by name and value */ -}; - - -/** - * Generic operation request. - */ -struct OperationRequest -{ - struct GNUNET_MessageHeader header; - - uint32_t reserved GNUNET_PACKED; - - /** - * Operation ID. - */ - uint64_t op_id GNUNET_PACKED; - - struct GNUNET_CRYPTO_EddsaPublicKey channel_key; -}; - - -/** - * @see GNUNET_PSYCSTORE_membership_store() - */ -struct MembershipStoreRequest -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_STORE - */ - struct GNUNET_MessageHeader header; - - uint32_t reserved GNUNET_PACKED; - - /** - * Operation ID. - */ - uint64_t op_id GNUNET_PACKED; - - /** - * Channel's public key. - */ - struct GNUNET_CRYPTO_EddsaPublicKey channel_key; - - /** - * Slave's public key. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey slave_key; - - uint64_t announced_at GNUNET_PACKED; - uint64_t effective_since GNUNET_PACKED; - uint64_t group_generation GNUNET_PACKED; - uint8_t did_join; -}; - - -/** - * @see GNUNET_PSYCSTORE_membership_test() - */ -struct MembershipTestRequest -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_TEST - */ - struct GNUNET_MessageHeader header; - - uint32_t reserved GNUNET_PACKED; - - /** - * Operation ID. - */ - uint64_t op_id GNUNET_PACKED; - - /** - * Channel's public key. - */ - struct GNUNET_CRYPTO_EddsaPublicKey channel_key; - - /** - * Slave's public key. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey slave_key; - - uint64_t message_id GNUNET_PACKED; - - uint64_t group_generation GNUNET_PACKED; -}; - - -/** - * @see GNUNET_PSYCSTORE_fragment_store() - */ -struct FragmentStoreRequest -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_STORE - */ - struct GNUNET_MessageHeader header; - - /** - * enum GNUNET_PSYCSTORE_MessageFlags - */ - uint32_t psycstore_flags GNUNET_PACKED; - - /** - * Channel's public key. - */ - struct GNUNET_CRYPTO_EddsaPublicKey channel_key; - - /** - * Operation ID. - */ - uint64_t op_id; - - /* Followed by fragment */ -}; - - -/** - * @see GNUNET_PSYCSTORE_fragment_get() - */ -struct FragmentGetRequest -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_GET - */ - struct GNUNET_MessageHeader header; - - uint32_t reserved GNUNET_PACKED; - - /** - * Operation ID. - */ - uint64_t op_id GNUNET_PACKED; - - /** - * Channel's public key. - */ - struct GNUNET_CRYPTO_EddsaPublicKey channel_key; - - /** - * Slave's public key. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey slave_key; - - /** - * First fragment ID to request. - */ - uint64_t first_fragment_id GNUNET_PACKED; - - /** - * Last fragment ID to request. - */ - uint64_t last_fragment_id GNUNET_PACKED; - - /** - * Maximum number of fragments to retrieve. - */ - uint64_t fragment_limit GNUNET_PACKED; - - /** - * Do membership test with @a slave_key before returning fragment? - * #GNUNET_YES or #GNUNET_NO - */ - uint8_t do_membership_test; -}; - - -/** - * @see GNUNET_PSYCSTORE_message_get() - */ -struct MessageGetRequest -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET - */ - struct GNUNET_MessageHeader header; - - uint32_t reserved GNUNET_PACKED; - - /** - * Operation ID. - */ - uint64_t op_id GNUNET_PACKED; - - /** - * Channel's public key. - */ - struct GNUNET_CRYPTO_EddsaPublicKey channel_key; - - /** - * Slave's public key. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey slave_key; - - /** - * First message ID to request. - */ - uint64_t first_message_id GNUNET_PACKED; - - /** - * Last message ID to request. - */ - uint64_t last_message_id GNUNET_PACKED; - - /** - * Maximum number of messages to retrieve. - */ - uint64_t message_limit GNUNET_PACKED; - - /** - * Maximum number of fragments to retrieve. - */ - uint64_t fragment_limit GNUNET_PACKED; - - /** - * Do membership test with @a slave_key before returning fragment? - * #GNUNET_YES or #GNUNET_NO - */ - uint8_t do_membership_test; - - /* Followed by method_prefix */ -}; - - -/** - * @see GNUNET_PSYCSTORE_message_get_fragment() - */ -struct MessageGetFragmentRequest -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_FRAGMENT_GET - */ - struct GNUNET_MessageHeader header; - - uint32_t reserved GNUNET_PACKED; - - /** - * Operation ID. - */ - uint64_t op_id GNUNET_PACKED; - - /** - * Channel's public key. - */ - struct GNUNET_CRYPTO_EddsaPublicKey channel_key; - - /** - * Slave's public key. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey slave_key; - - /** - * Requested message ID. - */ - uint64_t message_id GNUNET_PACKED; - - /** - * Requested fragment offset. - */ - uint64_t fragment_offset GNUNET_PACKED; - - /** - * Do membership test with @a slave_key before returning fragment? - * #GNUNET_YES or #GNUNET_NO - */ - uint8_t do_membership_test; -}; - - -/** - * @see GNUNET_PSYCSTORE_state_hash_update() - */ -struct StateHashUpdateRequest -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_HASH_UPDATE - */ - struct GNUNET_MessageHeader header; - - uint32_t reserved GNUNET_PACKED; - - /** - * Operation ID. - */ - uint64_t op_id GNUNET_PACKED; - - /** - * Channel's public key. - */ - struct GNUNET_CRYPTO_EddsaPublicKey channel_key; - - struct GNUNET_HashCode hash; -}; - - -enum StateOpFlags -{ - STATE_OP_FIRST = 1 << 0, - STATE_OP_LAST = 1 << 1 -}; - - -/** - * @see GNUNET_PSYCSTORE_state_modify() - */ -struct StateModifyRequest -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_MODIFY - */ - struct GNUNET_MessageHeader header; - - /** - * Operation ID. - */ - uint64_t op_id GNUNET_PACKED; - - /** - * ID of the message to apply the state changes in. - */ - uint64_t message_id GNUNET_PACKED; - - /** - * State delta of the message with ID @a message_id. - */ - uint64_t state_delta GNUNET_PACKED; - - /** - * Channel's public key. - */ - struct GNUNET_CRYPTO_EddsaPublicKey channel_key; -}; - - -/** - * @see GNUNET_PSYCSTORE_state_sync() - */ -struct StateSyncRequest -{ - /** - * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_SYNC - */ - struct GNUNET_MessageHeader header; - - /** - * Size of name, including NUL terminator. - */ - uint16_t name_size GNUNET_PACKED; - - /** - * OR'd StateOpFlags - */ - uint8_t flags; - - uint8_t reserved; - - /** - * Operation ID. - */ - uint64_t op_id GNUNET_PACKED; - - /** - * ID of the message that contains the state_hash PSYC header variable. - */ - uint64_t state_hash_message_id GNUNET_PACKED; - - /** - * ID of the last stateful message before @a state_hash_message_id. - */ - uint64_t max_state_message_id GNUNET_PACKED; - - /** - * Channel's public key. - */ - struct GNUNET_CRYPTO_EddsaPublicKey channel_key; - - /* Followed by NUL-terminated name, then the value. */ -}; - - -GNUNET_NETWORK_STRUCT_END - -#endif diff --git a/src/psycstore/psycstore_api.c b/src/psycstore/psycstore_api.c deleted file mode 100644 index ab4cd0fbf..000000000 --- a/src/psycstore/psycstore_api.c +++ /dev/null @@ -1,1285 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file psycstore/psycstore_api.c - * @brief API to interact with the PSYCstore service - * @author Gabor X Toth - * @author Christian Grothoff - */ - -#include - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_constants.h" -#include "gnunet_protocols.h" -#include "gnunet_psycstore_service.h" -#include "gnunet_multicast_service.h" -#include "psycstore.h" - -#define LOG(kind,...) GNUNET_log_from (kind, "psycstore-api",__VA_ARGS__) - -/** - * Handle for an operation with the PSYCstore service. - */ -struct GNUNET_PSYCSTORE_OperationHandle -{ - - /** - * Main PSYCstore handle. - */ - struct GNUNET_PSYCSTORE_Handle *h; - - /** - * Data callbacks. - */ - union { - GNUNET_PSYCSTORE_FragmentCallback fragment_cb; - GNUNET_PSYCSTORE_CountersCallback counters_cb; - GNUNET_PSYCSTORE_StateCallback state_cb; - }; - - /** - * Closure for callbacks. - */ - void *cls; - - /** - * Message envelope. - */ - struct GNUNET_MQ_Envelope *env; - - /** - * Operation ID. - */ - uint64_t op_id; -}; - - -/** - * Handle for the service. - */ -struct GNUNET_PSYCSTORE_Handle -{ - /** - * Configuration to use. - */ - const struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * Client connection. - */ - struct GNUNET_MQ_Handle *mq; - - /** - * Async operations. - */ - struct GNUNET_OP_Handle *op; - - /** - * Task doing exponential back-off trying to reconnect. - */ - struct GNUNET_SCHEDULER_Task *reconnect_task; - - /** - * Delay for next connect retry. - */ - struct GNUNET_TIME_Relative reconnect_delay; - - - GNUNET_PSYCSTORE_FragmentCallback *fragment_cb; - - GNUNET_PSYCSTORE_CountersCallback *counters_cb; - - GNUNET_PSYCSTORE_StateCallback *state_cb; - /** - * Closure for callbacks. - */ - void *cb_cls; -}; - - -static int -check_result_code (void *cls, const struct OperationResult *opres) -{ - uint16_t size = ntohs (opres->header.size); - const char *str = (const char *) &opres[1]; - if ( (sizeof (*opres) < size) && - ('\0' != str[size - sizeof (*opres) - 1]) ) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - - return GNUNET_OK; -} - - -static void -handle_result_code (void *cls, const struct OperationResult *opres) -{ - struct GNUNET_PSYCSTORE_Handle *h = cls; - struct GNUNET_PSYCSTORE_OperationHandle *op = NULL; - uint16_t size = ntohs (opres->header.size); - - const char * - str = (sizeof (*opres) < size) ? (const char *) &opres[1] : ""; - - if (GNUNET_YES == GNUNET_OP_result (h->op, GNUNET_ntohll (opres->op_id), - GNUNET_ntohll (opres->result_code) + INT64_MIN, - str, size - sizeof (*opres), (void **) &op)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "handle_result_code: Received result message with OP ID: %" PRIu64 "\n", - GNUNET_ntohll (opres->op_id)); - GNUNET_free (op); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "handle_result_code: No callback registered for OP ID %" PRIu64 ".\n", - GNUNET_ntohll (opres->op_id)); - } - h->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; -} - - -static void -handle_result_counters (void *cls, const struct CountersResult *cres) -{ - struct GNUNET_PSYCSTORE_Handle *h = cls; - struct GNUNET_PSYCSTORE_OperationHandle *op = NULL; - - if (GNUNET_YES == GNUNET_OP_get (h->op, GNUNET_ntohll (cres->op_id), - NULL, NULL, (void **) &op)) - { - GNUNET_assert (NULL != op); - if (NULL != op->counters_cb) - { - op->counters_cb (op->cls, - ntohl (cres->result_code), - GNUNET_ntohll (cres->max_fragment_id), - GNUNET_ntohll (cres->max_message_id), - GNUNET_ntohll (cres->max_group_generation), - GNUNET_ntohll (cres->max_state_message_id)); - } - GNUNET_OP_remove (h->op, GNUNET_ntohll (cres->op_id)); - GNUNET_free (op); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "handle_result_counters: No callback registered for OP ID %" PRIu64 ".\n", - GNUNET_ntohll (cres->op_id)); - } - h->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; -} - - -static int -check_result_fragment (void *cls, const struct FragmentResult *fres) -{ - uint16_t size = ntohs (fres->header.size); - struct GNUNET_MULTICAST_MessageHeader *mmsg = - (struct GNUNET_MULTICAST_MessageHeader *) &fres[1]; - if (sizeof (*fres) + sizeof (*mmsg) < size - && sizeof (*fres) + ntohs (mmsg->header.size) != size) - { - LOG (GNUNET_ERROR_TYPE_ERROR, - "check_result_fragment: Received message with invalid length %lu bytes.\n", - size, sizeof (*fres)); - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -static void -handle_result_fragment (void *cls, const struct FragmentResult *fres) -{ - struct GNUNET_PSYCSTORE_Handle *h = cls; - struct GNUNET_PSYCSTORE_OperationHandle *op = NULL; - - if (GNUNET_YES == GNUNET_OP_get (h->op, GNUNET_ntohll (fres->op_id), - NULL, NULL, (void **) &op)) - { - GNUNET_assert (NULL != op); - if (NULL != op->fragment_cb) - op->fragment_cb (op->cls, - (struct GNUNET_MULTICAST_MessageHeader *) &fres[1], - ntohl (fres->psycstore_flags)); - //GNUNET_OP_remove (h->op, GNUNET_ntohll (fres->op_id)); - //GNUNET_free (op); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "handle_result_fragment: No callback registered for OP ID %" PRIu64 ".\n", - GNUNET_ntohll (fres->op_id)); - } - h->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; -} - - -static int -check_result_state (void *cls, const struct StateResult *sres) -{ - const char *name = (const char *) &sres[1]; - uint16_t size = ntohs (sres->header.size); - uint16_t name_size = ntohs (sres->name_size); - - if (name_size <= 2 - || size - sizeof (*sres) < name_size - || '\0' != name[name_size - 1]) - { - LOG (GNUNET_ERROR_TYPE_ERROR, - "check_result_state: Received state result message with invalid name.\n"); - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -static void -handle_result_state (void *cls, const struct StateResult *sres) -{ - struct GNUNET_PSYCSTORE_Handle *h = cls; - struct GNUNET_PSYCSTORE_OperationHandle *op = NULL; - - const char *name = (const char *) &sres[1]; - uint16_t name_size = ntohs (sres->name_size); - - if (GNUNET_YES == GNUNET_OP_get (h->op, GNUNET_ntohll (sres->op_id), - NULL, NULL, (void **) &op)) - { - GNUNET_assert (NULL != op); - if (NULL != op->state_cb) - op->state_cb (op->cls, name, (char *) &sres[1] + name_size, - ntohs (sres->header.size) - sizeof (*sres) - name_size); - //GNUNET_OP_remove (h->op, GNUNET_ntohll (sres->op_id)); - //GNUNET_free (op); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "handle_result_state: No callback registered for OP ID %" PRIu64 ".\n", - GNUNET_ntohll (sres->op_id)); - } - h->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; -} - - -static void -reconnect (void *cls); - - -/** - * Client disconnected from service. - * - * Reconnect after backoff period.= - */ -static void -disconnected (void *cls, enum GNUNET_MQ_Error error) -{ - struct GNUNET_PSYCSTORE_Handle *h = cls; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Origin client disconnected (%d), re-connecting\n", - (int) error); - if (NULL != h->mq) - { - GNUNET_MQ_destroy (h->mq); - GNUNET_OP_destroy (h->op); - h->mq = NULL; - h->op = NULL; - } - - h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, - &reconnect, h); - h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay); -} - - -static void -do_connect (struct GNUNET_PSYCSTORE_Handle *h) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Connecting to PSYCstore service.\n"); - - struct GNUNET_MQ_MessageHandler handlers[] = { - GNUNET_MQ_hd_var_size (result_code, - GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE, - struct OperationResult, - h), - GNUNET_MQ_hd_fixed_size (result_counters, - GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_COUNTERS, - struct CountersResult, - h), - GNUNET_MQ_hd_var_size (result_fragment, - GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_FRAGMENT, - struct FragmentResult, - h), - GNUNET_MQ_hd_var_size (result_state, - GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_STATE, - struct StateResult, - h), - GNUNET_MQ_handler_end () - }; - - h->op = GNUNET_OP_create (); - GNUNET_assert (NULL == h->mq); - h->mq = GNUNET_CLIENT_connect (h->cfg, "psycstore", - handlers, disconnected, h); - GNUNET_assert (NULL != h->mq); -} - - -/** - * Try again to connect to the PSYCstore service. - * - * @param cls Handle to the PSYCstore service. - */ -static void -reconnect (void *cls) -{ - struct GNUNET_PSYCSTORE_Handle *h = cls; - - h->reconnect_task = NULL; - do_connect (cls); -} - - -/** - * Connect to the PSYCstore service. - * - * @param cfg The configuration to use - * @return Handle to use - */ -struct GNUNET_PSYCSTORE_Handle * -GNUNET_PSYCSTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct GNUNET_PSYCSTORE_Handle *h - = GNUNET_new (struct GNUNET_PSYCSTORE_Handle); - h->cfg = cfg; - h->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; - do_connect (h); - return h; -} - - -/** - * Disconnect from PSYCstore service - * - * @param h Handle to destroy - */ -void -GNUNET_PSYCSTORE_disconnect (struct GNUNET_PSYCSTORE_Handle *h) -{ - GNUNET_assert (NULL != h); - if (h->reconnect_task != NULL) - { - GNUNET_SCHEDULER_cancel (h->reconnect_task); - h->reconnect_task = NULL; - } - if (NULL != h->mq) - { - // FIXME: free data structures for pending operations - GNUNET_MQ_destroy (h->mq); - h->mq = NULL; - } - GNUNET_free (h); -} - - -/** - * Message sent notification. - * - * Remove invalidated envelope pointer. - */ -static void -message_sent (void *cls) -{ - struct GNUNET_PSYCSTORE_OperationHandle *op = cls; - op->env = NULL; -} - - -/** - * Create a new operation. - */ -static struct GNUNET_PSYCSTORE_OperationHandle * -op_create (struct GNUNET_PSYCSTORE_Handle *h, - struct GNUNET_OP_Handle *hop, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls) -{ - struct GNUNET_PSYCSTORE_OperationHandle * - op = GNUNET_malloc (sizeof (*op)); - op->h = h; - op->op_id = GNUNET_OP_add (hop, - (GNUNET_ResultCallback) result_cb, - cls, op); - return op; -} - - -/** - * Send a message associated with an operation. - * - * @param h - * PSYCstore handle. - * @param op - * Operation handle. - * @param env - * Message envelope to send. - * @param[out] op_id - * Operation ID to write in network byte order. NULL if not needed. - * - * @return Operation handle. - * - */ -static struct GNUNET_PSYCSTORE_OperationHandle * -op_send (struct GNUNET_PSYCSTORE_Handle *h, - struct GNUNET_PSYCSTORE_OperationHandle *op, - struct GNUNET_MQ_Envelope *env, - uint64_t *op_id) -{ - op->env = env; - if (NULL != op_id) - *op_id = GNUNET_htonll (op->op_id); - - GNUNET_MQ_notify_sent (env, message_sent, op); - GNUNET_MQ_send (h->mq, env); - return op; -} - - -/** - * Cancel a PSYCstore operation. Note that the operation MAY still - * be executed; this merely cancels the continuation; if the request - * was already transmitted, the service may still choose to complete - * the operation. - * - * @param op Operation to cancel. - * - * @return #GNUNET_YES if message was not sent yet and got discarded, - * #GNUNET_NO if it was already sent, and only the callbacks got cancelled. - */ -int -GNUNET_PSYCSTORE_operation_cancel (struct GNUNET_PSYCSTORE_OperationHandle *op) -{ - struct GNUNET_PSYCSTORE_Handle *h = op->h; - int ret = GNUNET_NO; - - if (NULL != op->env) - { - GNUNET_MQ_send_cancel (op->env); - ret = GNUNET_YES; - } - - GNUNET_OP_remove (h->op, op->op_id); - GNUNET_free (op); - - return ret; -} - - -/** - * Store join/leave events for a PSYC channel in order to be able to answer - * membership test queries later. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel where the event happened. - * @param slave_key - * Public key of joining/leaving slave. - * @param did_join - * #GNUNET_YES on join, #GNUNET_NO on part. - * @param announced_at - * ID of the message that announced the membership change. - * @param effective_since - * Message ID this membership change is in effect since. - * For joins it is <= announced_at, for parts it is always 0. - * @param group_generation - * In case of a part, the last group generation the slave has access to. - * It has relevance when a larger message have fragments with different - * group generations. - * @param result_cb - * Callback to call with the result of the storage operation. - * @param cls - * Closure for the callback. - * - * @return Operation handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_membership_store (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - int did_join, - uint64_t announced_at, - uint64_t effective_since, - uint64_t group_generation, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls) -{ - GNUNET_assert (NULL != h); - GNUNET_assert (NULL != channel_key); - GNUNET_assert (NULL != slave_key); - GNUNET_assert (GNUNET_YES == did_join || GNUNET_NO == did_join); - GNUNET_assert (did_join - ? effective_since <= announced_at - : effective_since == 0); - - struct MembershipStoreRequest *req; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_STORE); - req->channel_key = *channel_key; - req->slave_key = *slave_key; - req->did_join = did_join; - req->announced_at = GNUNET_htonll (announced_at); - req->effective_since = GNUNET_htonll (effective_since); - req->group_generation = GNUNET_htonll (group_generation); - - return - op_send (h, op_create (h, h->op, result_cb, cls), - env, &req->op_id); -} - - -/** - * Test if a member was admitted to the channel at the given message ID. - * - * This is useful when relaying and replaying messages to check if a particular - * slave has access to the message fragment with a given group generation. It - * is also used when handling join requests to determine whether the slave is - * currently admitted to the channel. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param slave_key - * Public key of slave whose membership to check. - * @param message_id - * Message ID for which to do the membership test. - * @param group_generation - * Group generation of the fragment of the message to test. - * It has relevance if the message consists of multiple fragments with - * different group generations. - * @param result_cb - * Callback to call with the test result. - * @param cls - * Closure for the callback. - * - * @return Operation handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_membership_test (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - uint64_t message_id, - uint64_t group_generation, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls) -{ - struct MembershipTestRequest *req; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_TEST); - req->channel_key = *channel_key; - req->slave_key = *slave_key; - req->message_id = GNUNET_htonll (message_id); - req->group_generation = GNUNET_htonll (group_generation); - - return - op_send (h, op_create (h, h->op, result_cb, cls), - env, &req->op_id); -} - - -/** - * Store a message fragment sent to a channel. - * - * @param h Handle for the PSYCstore. - * @param channel_key The channel the message belongs to. - * @param message Message to store. - * @param psycstore_flags Flags indicating whether the PSYC message contains - * state modifiers. - * @param result_cb Callback to call with the result of the operation. - * @param cls Closure for the callback. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_fragment_store (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_MULTICAST_MessageHeader *msg, - enum GNUNET_PSYCSTORE_MessageFlags psycstore_flags, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls) -{ - uint16_t size = ntohs (msg->header.size); - struct FragmentStoreRequest *req; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (req, size, - GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_STORE); - req->channel_key = *channel_key; - req->psycstore_flags = htonl (psycstore_flags); - GNUNET_memcpy (&req[1], msg, size); - - return - op_send (h, op_create (h, h->op, result_cb, cls), - env, &req->op_id); -} - - -/** - * Retrieve message fragments by fragment ID range. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param slave_key - * The slave requesting the fragment. If not NULL, a membership test is - * performed first and the fragment is only returned if the slave has - * access to it. - * @param first_fragment_id - * First fragment ID to retrieve. - * Use 0 to get the latest message fragment. - * @param last_fragment_id - * Last consecutive fragment ID to retrieve. - * Use 0 to get the latest message fragment. - * @param fragment_limit - * Maximum number of fragments to retrieve. - * @param fragment_cb - * Callback to call with the retrieved fragments. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for the callbacks. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_fragment_get (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - uint64_t first_fragment_id, - uint64_t last_fragment_id, - GNUNET_PSYCSTORE_FragmentCallback fragment_cb, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls) -{ - struct FragmentGetRequest *req; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_GET); - req->channel_key = *channel_key; - req->first_fragment_id = GNUNET_htonll (first_fragment_id); - req->last_fragment_id = GNUNET_htonll (last_fragment_id); - if (NULL != slave_key) - { - req->slave_key = *slave_key; - req->do_membership_test = GNUNET_YES; - } - - struct GNUNET_PSYCSTORE_OperationHandle * - op = op_create (h, h->op, result_cb, cls); - op->fragment_cb = fragment_cb; - op->cls = cls; - return op_send (h, op, env, &req->op_id); -} - - -/** - * Retrieve latest message fragments. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param slave_key - * The slave requesting the fragment. If not NULL, a membership test is - * performed first and the fragment is only returned if the slave has - * access to it. - * @param first_fragment_id - * First fragment ID to retrieve. - * Use 0 to get the latest message fragment. - * @param last_fragment_id - * Last consecutive fragment ID to retrieve. - * Use 0 to get the latest message fragment. - * @param fragment_limit - * Maximum number of fragments to retrieve. - * @param fragment_cb - * Callback to call with the retrieved fragments. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for the callbacks. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_fragment_get_latest (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - uint64_t fragment_limit, - GNUNET_PSYCSTORE_FragmentCallback fragment_cb, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls) -{ - struct FragmentGetRequest *req; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_GET); - req->channel_key = *channel_key; - req->fragment_limit = GNUNET_ntohll (fragment_limit); - if (NULL != slave_key) - { - req->slave_key = *slave_key; - req->do_membership_test = GNUNET_YES; - } - - struct GNUNET_PSYCSTORE_OperationHandle * - op = op_create (h, h->op, result_cb, cls); - op->fragment_cb = fragment_cb; - op->cls = cls; - return op_send (h, op, env, &req->op_id); -} - - -/** - * Retrieve all fragments of messages in a message ID range. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param slave_key - * The slave requesting the message. - * If not NULL, a membership test is performed first - * and the message is only returned if the slave has access to it. - * @param first_message_id - * First message ID to retrieve. - * @param last_message_id - * Last consecutive message ID to retrieve. - * @param fragment_limit - * Maximum number of fragments to retrieve. - * @param method_prefix - * Retrieve only messages with a matching method prefix. - * @todo Implement method_prefix query. - * @param fragment_cb - * Callback to call with the retrieved fragments. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for the callbacks. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_message_get (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - uint64_t first_message_id, - uint64_t last_message_id, - uint64_t fragment_limit, - const char *method_prefix, - GNUNET_PSYCSTORE_FragmentCallback fragment_cb, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls) -{ - struct MessageGetRequest *req; - if (NULL == method_prefix) - method_prefix = ""; - uint16_t method_size = strnlen (method_prefix, - GNUNET_MAX_MESSAGE_SIZE - - sizeof (*req)) + 1; - - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (req, method_size, - GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET); - req->channel_key = *channel_key; - req->first_message_id = GNUNET_htonll (first_message_id); - req->last_message_id = GNUNET_htonll (last_message_id); - req->fragment_limit = GNUNET_htonll (fragment_limit); - if (NULL != slave_key) - { - req->slave_key = *slave_key; - req->do_membership_test = GNUNET_YES; - } - GNUNET_memcpy (&req[1], method_prefix, method_size); - ((char *) &req[1])[method_size - 1] = '\0'; - - struct GNUNET_PSYCSTORE_OperationHandle * - op = op_create (h, h->op, result_cb, cls); - op->fragment_cb = fragment_cb; - op->cls = cls; - return op_send (h, op, env, &req->op_id); -} - - -/** - * Retrieve all fragments of the latest messages. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param slave_key - * The slave requesting the message. - * If not NULL, a membership test is performed first - * and the message is only returned if the slave has access to it. - * @param message_limit - * Maximum number of messages to retrieve. - * @param method_prefix - * Retrieve only messages with a matching method prefix. - * @todo Implement method_prefix query. - * @param fragment_cb - * Callback to call with the retrieved fragments. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for the callbacks. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_message_get_latest (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - uint64_t message_limit, - const char *method_prefix, - GNUNET_PSYCSTORE_FragmentCallback fragment_cb, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls) -{ - struct MessageGetRequest *req; - - if (NULL == method_prefix) - method_prefix = ""; - uint16_t method_size = strnlen (method_prefix, - GNUNET_MAX_MESSAGE_SIZE - - sizeof (*req)) + 1; - GNUNET_assert ('\0' == method_prefix[method_size - 1]); - - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (req, method_size, - GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET); - req->channel_key = *channel_key; - req->message_limit = GNUNET_ntohll (message_limit); - if (NULL != slave_key) - { - req->slave_key = *slave_key; - req->do_membership_test = GNUNET_YES; - } - GNUNET_memcpy (&req[1], method_prefix, method_size); - - struct GNUNET_PSYCSTORE_OperationHandle * - op = op_create (h, h->op, result_cb, cls); - op->fragment_cb = fragment_cb; - op->cls = cls; - return op_send (h, op, env, &req->op_id); -} - - -/** - * Retrieve a fragment of message specified by its message ID and fragment - * offset. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param slave_key - * The slave requesting the message fragment. If not NULL, a membership - * test is performed first and the message fragment is only returned - * if the slave has access to it. - * @param message_id - * Message ID to retrieve. Use 0 to get the latest message. - * @param fragment_offset - * Offset of the fragment to retrieve. - * @param fragment_cb - * Callback to call with the retrieved fragments. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for the callbacks. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_message_get_fragment (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - uint64_t message_id, - uint64_t fragment_offset, - GNUNET_PSYCSTORE_FragmentCallback fragment_cb, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls) -{ - struct MessageGetFragmentRequest *req; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET_FRAGMENT); - - req->channel_key = *channel_key; - req->message_id = GNUNET_htonll (message_id); - req->fragment_offset = GNUNET_htonll (fragment_offset); - if (NULL != slave_key) - { - req->slave_key = *slave_key; - req->do_membership_test = GNUNET_YES; - } - - struct GNUNET_PSYCSTORE_OperationHandle * - op = op_create (h, h->op, result_cb, cls); - op->fragment_cb = fragment_cb; - op->cls = cls; - return op_send (h, op, env, &req->op_id); -} - - -/** - * Retrieve latest values of counters for a channel master. - * - * The current value of counters are needed when a channel master is restarted, - * so that it can continue incrementing the counters from their last value. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * Public key that identifies the channel. - * @param ccb - * Callback to call with the result. - * @param ccb_cls - * Closure for the @a ccb callback. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_counters_get (struct GNUNET_PSYCSTORE_Handle *h, - struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - GNUNET_PSYCSTORE_CountersCallback counters_cb, - void *cls) -{ - struct OperationRequest *req; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_COUNTERS_GET); - req->channel_key = *channel_key; - - struct GNUNET_PSYCSTORE_OperationHandle * - op = op_create (h, h->op, NULL, NULL); - op->counters_cb = counters_cb; - op->cls = cls; - return op_send (h, op, env, &req->op_id); -} - - -/** - * Apply modifiers of a message to the current channel state. - * - * An error is returned if there are missing messages containing state - * operations before the current one. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param message_id - * ID of the message that contains the @a modifiers. - * @param state_delta - * Value of the _state_delta PSYC header variable of the message. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for @a result_cb. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_state_modify (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id, - uint64_t state_delta, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls) -{ - struct StateModifyRequest *req; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_MODIFY); - req->channel_key = *channel_key; - req->message_id = GNUNET_htonll (message_id); - req->state_delta = GNUNET_htonll (state_delta); - - return op_send (h, op_create (h, h->op, result_cb, cls), - env, &req->op_id); -} - - -struct StateSyncClosure -{ - GNUNET_PSYCSTORE_ResultCallback result_cb; - void *cls; - uint8_t last; -}; - - -static void -state_sync_result (void *cls, int64_t result, - const char *err_msg, uint16_t err_msg_size) -{ - struct StateSyncClosure *ssc = cls; - if (GNUNET_OK != result || ssc->last) - ssc->result_cb (ssc->cls, result, err_msg, err_msg_size); - GNUNET_free (ssc); -} - - -/** - * Store synchronized state. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param max_state_message_id - * ID of the last stateful message before @a state_hash_message_id. - * @param state_hash_message_id - * ID of the message that contains the state_hash PSYC header variable. - * @param modifier_count - * Number of elements in the @a modifiers array. - * @param modifiers - * Full state to store. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for the callback. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_state_sync (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t max_state_message_id, - uint64_t state_hash_message_id, - size_t modifier_count, - const struct GNUNET_PSYC_Modifier *modifiers, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls) -{ - struct GNUNET_PSYCSTORE_OperationHandle *op = NULL; - size_t i; - - for (i = 0; i < modifier_count; i++) { - struct StateSyncRequest *req; - uint16_t name_size = strlen (modifiers[i].name) + 1; - - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (req, - sizeof (*req) + name_size + modifiers[i].value_size, - GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_SYNC); - - req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_SYNC); - req->header.size = htons (sizeof (*req) + name_size - + modifiers[i].value_size); - req->channel_key = *channel_key; - req->max_state_message_id = GNUNET_htonll (max_state_message_id); - req->state_hash_message_id = GNUNET_htonll (state_hash_message_id); - req->name_size = htons (name_size); - req->flags - = (0 == i) - ? STATE_OP_FIRST - : (modifier_count - 1 == i) - ? STATE_OP_LAST - : 0; - - GNUNET_memcpy (&req[1], modifiers[i].name, name_size); - GNUNET_memcpy ((char *) &req[1] + name_size, modifiers[i].value, modifiers[i].value_size); - - struct StateSyncClosure *ssc = GNUNET_malloc (sizeof (*ssc)); - ssc->last = (req->flags & STATE_OP_LAST); - ssc->result_cb = result_cb; - ssc->cls = cls; - - op_send (h, op_create (h, h->op, state_sync_result, ssc), - env, &req->op_id); - } - // FIXME: only one operation is returned, - // add pointers to other operations and make all cancellable. - return op; -} - - -/** - * Reset the state of a channel. - * - * Delete all state variables stored for the given channel. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for the callback. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_state_reset (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey - *channel_key, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls) -{ - struct OperationRequest *req; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_RESET); - req->channel_key = *channel_key; - - return - op_send (h, op_create (h, h->op, result_cb, cls), - env, &req->op_id); -} - - -/** - * Update signed values of state variables in the state store. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param message_id - * Message ID that contained the state @a hash. - * @param hash - * Hash of the serialized full state. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for the callback. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_state_hash_update (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - uint64_t message_id, - const struct GNUNET_HashCode *hash, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls) -{ - struct StateHashUpdateRequest *req; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_HASH_UPDATE); - req->channel_key = *channel_key; - req->hash = *hash; - - return - op_send (h, op_create (h, h->op, result_cb, cls), - env, &req->op_id); -} - - -/** - * Retrieve the best matching state variable. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param name - * Name of variable to match, the returned variable might be less specific. - * @param state_cb - * Callback to return the matching state variable. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for the callbacks. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_state_get (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const char *name, - GNUNET_PSYCSTORE_StateCallback state_cb, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls) -{ - size_t name_size = strlen (name) + 1; - struct OperationRequest *req; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (req, name_size, - GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_GET); - req->channel_key = *channel_key; - GNUNET_memcpy (&req[1], name, name_size); - - struct GNUNET_PSYCSTORE_OperationHandle * - op = op_create (h, h->op, result_cb, cls); - op->state_cb = state_cb; - op->cls = cls; - return op_send (h, op, env, &req->op_id); -} - - -/** - * Retrieve all state variables for a channel with the given prefix. - * - * @param h - * Handle for the PSYCstore. - * @param channel_key - * The channel we are interested in. - * @param name_prefix - * Prefix of state variable names to match. - * @param state_cb - * Callback to return matching state variables. - * @param result_cb - * Callback to call with the result of the operation. - * @param cls - * Closure for the callbacks. - * - * @return Handle that can be used to cancel the operation. - */ -struct GNUNET_PSYCSTORE_OperationHandle * -GNUNET_PSYCSTORE_state_get_prefix (struct GNUNET_PSYCSTORE_Handle *h, - const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, - const char *name_prefix, - GNUNET_PSYCSTORE_StateCallback state_cb, - GNUNET_PSYCSTORE_ResultCallback result_cb, - void *cls) -{ - size_t name_size = strlen (name_prefix) + 1; - struct OperationRequest *req; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (req, name_size, - GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_GET_PREFIX); - req->channel_key = *channel_key; - GNUNET_memcpy (&req[1], name_prefix, name_size); - - struct GNUNET_PSYCSTORE_OperationHandle * - op = op_create (h, h->op, result_cb, cls); - op->state_cb = state_cb; - op->cls = cls; - return op_send (h, op, env, &req->op_id); -} - -/* end of psycstore_api.c */ diff --git a/src/psycstore/test_plugin_psycstore.c b/src/psycstore/test_plugin_psycstore.c deleted file mode 100644 index ff4eac820..000000000 --- a/src/psycstore/test_plugin_psycstore.c +++ /dev/null @@ -1,532 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @author Gabor X Toth - * @author Christian Grothoff - * - * @file - * Test for the PSYCstore plugins. - */ - -#include - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_testing_lib.h" -#include "gnunet_psycstore_plugin.h" -#include "gnunet_psycstore_service.h" -#include "gnunet_multicast_service.h" - -#define DEBUG_PSYCSTORE GNUNET_EXTRA_LOGGING -#if DEBUG_PSYCSTORE -# define LOG_LEVEL "DEBUG" -#else -# define LOG_LEVEL "WARNING" -#endif - -#define C2ARG(str) str, (sizeof (str) - 1) - -#define LOG(kind,...) \ - GNUNET_log_from (kind, "test-plugin-psycstore", __VA_ARGS__) - -static int ok; - -/** - * Name of plugin under test. - */ -static const char *plugin_name; - -static struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key; -static struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key; - -static struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key; -static struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; - -/** - * Function called when the service shuts down. Unloads our psycstore - * plugin. - * - * @param api api to unload - */ -static void -unload_plugin (struct GNUNET_PSYCSTORE_PluginFunctions *api) -{ - char *libname; - - GNUNET_asprintf (&libname, "libgnunet_plugin_psycstore_%s", plugin_name); - GNUNET_break (NULL == GNUNET_PLUGIN_unload (libname, api)); - GNUNET_free (libname); -} - - -/** - * Load the psycstore plugin. - * - * @param cfg configuration to pass - * @return NULL on error - */ -static struct GNUNET_PSYCSTORE_PluginFunctions * -load_plugin (const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct GNUNET_PSYCSTORE_PluginFunctions *ret; - char *libname; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Loading `%s' psycstore plugin\n"), - plugin_name); - GNUNET_asprintf (&libname, "libgnunet_plugin_psycstore_%s", plugin_name); - if (NULL == (ret = GNUNET_PLUGIN_load (libname, (void*) cfg))) - { - FPRINTF (stderr, "Failed to load plugin `%s'!\n", plugin_name); - return NULL; - } - GNUNET_free (libname); - return ret; -} - - -#define MAX_MSG 16 - -struct FragmentClosure -{ - uint8_t n; - uint64_t flags[MAX_MSG]; - struct GNUNET_MULTICAST_MessageHeader *msg[MAX_MSG]; -}; - -static int -fragment_cb (void *cls, struct GNUNET_MULTICAST_MessageHeader *msg2, - enum GNUNET_PSYCSTORE_MessageFlags flags) -{ - struct FragmentClosure *fcls = cls; - struct GNUNET_MULTICAST_MessageHeader *msg1; - uint64_t flags1; - int ret; - - if (fcls->n >= MAX_MSG) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - msg1 = fcls->msg[fcls->n]; - flags1 = fcls->flags[fcls->n++]; - if (NULL == msg1) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - - if (flags1 == flags && msg1->header.size == msg2->header.size - && 0 == memcmp (msg1, msg2, ntohs (msg1->header.size))) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "Fragment %llu matches\n", - GNUNET_ntohll (msg1->fragment_id)); - ret = GNUNET_YES; - } - else - { - LOG (GNUNET_ERROR_TYPE_ERROR, "Fragment %llu differs\n", - GNUNET_ntohll (msg1->fragment_id)); - ret = GNUNET_SYSERR; - } - - GNUNET_free (msg2); - return ret; -} - - -struct StateClosure { - size_t n; - char *name[16]; - void *value[16]; - size_t value_size[16]; -}; - -static int -state_cb (void *cls, const char *name, const void *value, uint32_t value_size) -{ - struct StateClosure *scls = cls; - const void *val = scls->value[scls->n]; // FIXME: check for n out-of-bounds FIRST! - size_t val_size = scls->value_size[scls->n++]; - - /* FIXME: check name */ - - LOG (GNUNET_ERROR_TYPE_DEBUG, - " name = %s, value_size = %u\n", - name, value_size); - - return GNUNET_YES; - return value_size == val_size && 0 == memcmp (value, val, val_size) - ? GNUNET_YES - : GNUNET_SYSERR; -} - - -static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct GNUNET_PSYCSTORE_PluginFunctions *db; - - ok = 1; - db = load_plugin (cfg); - if (NULL == db) - { - FPRINTF (stderr, - "%s", - "Failed to initialize PSYCstore. " - "Database likely not setup, skipping test.\n"); - ok = 77; - return; - } - - /* Store & test membership */ - - LOG (GNUNET_ERROR_TYPE_INFO, "MEMBERSHIP\n"); - - channel_key = GNUNET_CRYPTO_eddsa_key_create (); - slave_key = GNUNET_CRYPTO_ecdsa_key_create (); - - GNUNET_CRYPTO_eddsa_key_get_public (channel_key, - &channel_pub_key); - GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key); - - LOG (GNUNET_ERROR_TYPE_INFO, "membership_store()\n"); - - GNUNET_assert (GNUNET_OK == db->membership_store (db->cls, &channel_pub_key, - &slave_pub_key, GNUNET_YES, - 4, 2, 1)); - - LOG (GNUNET_ERROR_TYPE_INFO, "membership_test()\n"); - - GNUNET_assert (GNUNET_YES == db->membership_test (db->cls, &channel_pub_key, - &slave_pub_key, 4)); - - GNUNET_assert (GNUNET_YES == db->membership_test (db->cls, &channel_pub_key, - &slave_pub_key, 2)); - - GNUNET_assert (GNUNET_NO == db->membership_test (db->cls, &channel_pub_key, - &slave_pub_key, 1)); - - /* Store & get messages */ - - LOG (GNUNET_ERROR_TYPE_INFO, "MESSAGES\n"); - - struct GNUNET_MULTICAST_MessageHeader *msg - = GNUNET_malloc (sizeof (*msg) + sizeof (channel_pub_key)); - GNUNET_assert (msg != NULL); - - msg->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE); - msg->header.size = htons (sizeof (*msg) + sizeof (channel_pub_key)); - - uint64_t fragment_id = INT64_MAX - 1; - msg->fragment_id = GNUNET_htonll (fragment_id); - - uint64_t message_id = INT64_MAX - 10; - msg->message_id = GNUNET_htonll (message_id); - - uint64_t group_generation = INT64_MAX - 3; - msg->group_generation = GNUNET_htonll (group_generation); - - msg->hop_counter = htonl (9); - msg->fragment_offset = GNUNET_htonll (0); - msg->flags = htonl (GNUNET_MULTICAST_MESSAGE_LAST_FRAGMENT); - - GNUNET_memcpy (&msg[1], &channel_pub_key, sizeof (channel_pub_key)); - - msg->purpose.size = htonl (ntohs (msg->header.size) - - sizeof (msg->header) - - sizeof (msg->hop_counter) - - sizeof (msg->signature)); - msg->purpose.purpose = htonl (234); - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_eddsa_sign (channel_key, &msg->purpose, &msg->signature)); - - LOG (GNUNET_ERROR_TYPE_INFO, "fragment_store()\n"); - - struct FragmentClosure fcls = { 0 }; - fcls.n = 0; - fcls.msg[0] = msg; - fcls.flags[0] = GNUNET_PSYCSTORE_MESSAGE_STATE; - - GNUNET_assert ( - GNUNET_OK == db->fragment_store (db->cls, &channel_pub_key, msg, - fcls.flags[0])); - - LOG (GNUNET_ERROR_TYPE_INFO, "fragment_get(%" PRIu64 ")\n", fragment_id); - - uint64_t ret_frags = 0; - GNUNET_assert ( - GNUNET_OK == db->fragment_get (db->cls, &channel_pub_key, - fragment_id, fragment_id, - &ret_frags, fragment_cb, &fcls)); - GNUNET_assert (fcls.n == 1); - - LOG (GNUNET_ERROR_TYPE_INFO, "message_get_fragment()\n"); - - fcls.n = 0; - GNUNET_assert ( - GNUNET_OK == db->message_get_fragment (db->cls, &channel_pub_key, - GNUNET_ntohll (msg->message_id), - GNUNET_ntohll (msg->fragment_offset), - fragment_cb, &fcls)); - GNUNET_assert (fcls.n == 1); - - LOG (GNUNET_ERROR_TYPE_INFO, "message_add_flags()\n"); - GNUNET_assert ( - GNUNET_OK == db->message_add_flags (db->cls, &channel_pub_key, - GNUNET_ntohll (msg->message_id), - GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED)); - LOG (GNUNET_ERROR_TYPE_INFO, "fragment_get(%" PRIu64 ")\n", fragment_id); - - fcls.n = 0; - fcls.flags[0] |= GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED; - - GNUNET_assert ( - GNUNET_OK == db->fragment_get (db->cls, &channel_pub_key, - fragment_id, fragment_id, - &ret_frags, fragment_cb, &fcls)); - - GNUNET_assert (fcls.n == 1); - - LOG (GNUNET_ERROR_TYPE_INFO, "fragment_store()\n"); - - struct GNUNET_MULTICAST_MessageHeader *msg1 - = GNUNET_malloc (sizeof (*msg1) + sizeof (channel_pub_key)); - - GNUNET_memcpy (msg1, msg, sizeof (*msg1) + sizeof (channel_pub_key)); - - msg1->fragment_id = GNUNET_htonll (INT64_MAX); - msg1->fragment_offset = GNUNET_htonll (32768); - - fcls.n = 0; - fcls.msg[1] = msg1; - fcls.flags[1] = GNUNET_PSYCSTORE_MESSAGE_STATE_HASH; - - GNUNET_assert (GNUNET_OK == db->fragment_store (db->cls, &channel_pub_key, msg1, - fcls.flags[1])); - - LOG (GNUNET_ERROR_TYPE_INFO, "message_get()\n"); - - GNUNET_assert ( - GNUNET_OK == db->message_get (db->cls, &channel_pub_key, - message_id, message_id, 0, - &ret_frags, fragment_cb, &fcls)); - GNUNET_assert (fcls.n == 2 && ret_frags == 2); - - /* Message counters */ - - LOG (GNUNET_ERROR_TYPE_INFO, "counters_message_get()\n"); - - fragment_id = 0; - message_id = 0; - group_generation = 0; - GNUNET_assert ( - GNUNET_OK == db->counters_message_get (db->cls, &channel_pub_key, - &fragment_id, &message_id, - &group_generation) - && fragment_id == GNUNET_ntohll (msg1->fragment_id) - && message_id == GNUNET_ntohll (msg1->message_id) - && group_generation == GNUNET_ntohll (msg1->group_generation)); - - /* Modify state */ - - LOG (GNUNET_ERROR_TYPE_INFO, "STATE\n"); - - LOG (GNUNET_ERROR_TYPE_INFO, "state_modify_*()\n"); - - message_id = GNUNET_ntohll (fcls.msg[0]->message_id) + 1; - GNUNET_assert (GNUNET_OK == db->state_modify_begin (db->cls, &channel_pub_key, - message_id, 0)); - - GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key, - GNUNET_PSYC_OP_ASSIGN, - "_foo", - C2ARG("one two three"))); - - GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key, - GNUNET_PSYC_OP_ASSIGN, - "_foo_bar", slave_key, - sizeof (*slave_key))); - - GNUNET_assert (GNUNET_OK == db->state_modify_end (db->cls, &channel_pub_key, - message_id)); - - LOG (GNUNET_ERROR_TYPE_INFO, "state_get()\n"); - - struct StateClosure scls = { 0 }; - scls.n = 0; - scls.value[0] = "one two three"; - scls.value_size[0] = strlen ("one two three"); - - GNUNET_assert (GNUNET_OK == db->state_get (db->cls, &channel_pub_key, "_foo", - state_cb, &scls)); - GNUNET_assert (scls.n == 1); - - LOG (GNUNET_ERROR_TYPE_INFO, "state_get_prefix()\n"); - - scls.n = 0; - scls.value[1] = slave_key; - scls.value_size[1] = sizeof (*slave_key); - - GNUNET_assert (GNUNET_OK == db->state_get_prefix (db->cls, &channel_pub_key, - "_foo", state_cb, &scls)); - GNUNET_assert (scls.n == 2); - - LOG (GNUNET_ERROR_TYPE_INFO, "state_get_signed()\n"); - - scls.n = 0; - GNUNET_assert (GNUNET_NO == db->state_get_signed (db->cls, &channel_pub_key, - state_cb, &scls)); - GNUNET_assert (scls.n == 0); - - LOG (GNUNET_ERROR_TYPE_INFO, "state_update_signed()\n"); - - GNUNET_assert (GNUNET_OK == db->state_update_signed (db->cls, - &channel_pub_key)); - - LOG (GNUNET_ERROR_TYPE_INFO, "state_get_signed()\n"); - - scls.n = 0; - GNUNET_assert (GNUNET_YES == db->state_get_signed (db->cls, &channel_pub_key, - state_cb, &scls)); - GNUNET_assert (scls.n == 2); - - /* State counters */ - - LOG (GNUNET_ERROR_TYPE_INFO, "counters_state_get()\n"); - - uint64_t max_state_msg_id = 0; - GNUNET_assert (GNUNET_OK == db->counters_state_get (db->cls, &channel_pub_key, - &max_state_msg_id) - && max_state_msg_id == message_id); - - /* State sync */ - - LOG (GNUNET_ERROR_TYPE_INFO, "state_sync_*()\n"); - - scls.n = 0; - scls.value[0] = channel_key; - scls.value_size[0] = sizeof (*channel_key); - scls.value[1] = "three two one"; - scls.value_size[1] = strlen ("three two one"); - - GNUNET_assert (GNUNET_OK == db->state_sync_begin (db->cls, &channel_pub_key)); - - GNUNET_assert (GNUNET_OK == db->state_sync_assign (db->cls, &channel_pub_key, - "_sync_bar", scls.value[0], - scls.value_size[0])); - - GNUNET_assert (GNUNET_OK == db->state_sync_assign (db->cls, &channel_pub_key, - "_sync_foo", scls.value[1], - scls.value_size[1])); - - GNUNET_assert (GNUNET_OK == db->state_sync_end (db->cls, &channel_pub_key, - max_state_msg_id, - INT64_MAX - 5)); - - GNUNET_assert (GNUNET_NO == db->state_get_prefix (db->cls, &channel_pub_key, - "_foo", state_cb, &scls)); - GNUNET_assert (scls.n == 0); - - GNUNET_assert (GNUNET_OK == db->state_get_prefix (db->cls, &channel_pub_key, - "_sync", state_cb, &scls)); - GNUNET_assert (scls.n == 2); - - scls.n = 0; - GNUNET_assert (GNUNET_OK == db->state_get_signed (db->cls, &channel_pub_key, - state_cb, &scls)); - GNUNET_assert (scls.n == 2); - - /* Modify state after sync */ - - LOG (GNUNET_ERROR_TYPE_INFO, "state_modify_*()\n"); - - message_id = GNUNET_ntohll (fcls.msg[0]->message_id) + 6; - GNUNET_assert (GNUNET_OK == db->state_modify_begin (db->cls, &channel_pub_key, - message_id, - message_id - max_state_msg_id)); - - GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key, - GNUNET_PSYC_OP_ASSIGN, - "_sync_foo", - C2ARG("five six seven"))); - - GNUNET_assert (GNUNET_OK == db->state_modify_end (db->cls, &channel_pub_key, - message_id)); - - /* Reset state */ - - LOG (GNUNET_ERROR_TYPE_INFO, "state_reset()\n"); - - scls.n = 0; - GNUNET_assert (GNUNET_OK == db->state_reset (db->cls, &channel_pub_key)); - GNUNET_assert (scls.n == 0); - - ok = 0; - - if (NULL != channel_key) - { - GNUNET_free (channel_key); - channel_key = NULL; - } - if (NULL != slave_key) - { - GNUNET_free (slave_key); - slave_key = NULL; - } - - unload_plugin (db); -} - - -int -main (int argc, char *argv[]) -{ - char cfg_name[128]; - char *const xargv[] = { - "test-plugin-psycstore", - "-c", cfg_name, - "-L", LOG_LEVEL, - NULL - }; - struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_OPTION_END - }; - GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-psycstore-sqlite"); - GNUNET_log_setup ("test-plugin-psycstore", LOG_LEVEL, NULL); - plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]); - GNUNET_snprintf (cfg_name, sizeof (cfg_name), "test_plugin_psycstore_%s.conf", - plugin_name); - GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1, xargv, - "test-plugin-psycstore", "nohelp", options, &run, NULL); - - if ( (0 != ok) && - (77 != ok) ) - FPRINTF (stderr, "Missed some testcases: %d\n", ok); - -#if ! DEBUG_PSYCSTORE - GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-psycstore-sqlite"); -#endif - - return ok; -} - -/* end of test_plugin_psycstore.c */ diff --git a/src/psycstore/test_plugin_psycstore_mysql.conf b/src/psycstore/test_plugin_psycstore_mysql.conf deleted file mode 100644 index e15b3fd63..000000000 --- a/src/psycstore/test_plugin_psycstore_mysql.conf +++ /dev/null @@ -1,7 +0,0 @@ -[psycstore-mysql] -DATABASE = test -# CONFIG = ~/.my.cnf -# USER = gnunet -# PASSWORD = -# HOST = localhost -# PORT = 3306 diff --git a/src/psycstore/test_plugin_psycstore_postgres.conf b/src/psycstore/test_plugin_psycstore_postgres.conf deleted file mode 100644 index 4b870dd02..000000000 --- a/src/psycstore/test_plugin_psycstore_postgres.conf +++ /dev/null @@ -1,2 +0,0 @@ -[psycstore-postgres] -CONFIG = connect_timeout=10; dbname=template1 diff --git a/src/psycstore/test_plugin_psycstore_sqlite.conf b/src/psycstore/test_plugin_psycstore_sqlite.conf deleted file mode 100644 index 498b1d02d..000000000 --- a/src/psycstore/test_plugin_psycstore_sqlite.conf +++ /dev/null @@ -1,2 +0,0 @@ -[psycstore-sqlite] -FILENAME = $GNUNET_TMP/gnunet-test-plugin-psycstore-sqlite/sqlite.db diff --git a/src/psycstore/test_psycstore.c b/src/psycstore/test_psycstore.c deleted file mode 100644 index ca509041c..000000000 --- a/src/psycstore/test_psycstore.c +++ /dev/null @@ -1,586 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file psycstore/test_psycstore.c - * @brief Test for the PSYCstore service. - * @author Gabor X Toth - * @author Christian Grothoff - */ - -#include - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_common.h" -#include "gnunet_testing_lib.h" -#include "gnunet_psycstore_service.h" - -#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) - - -/** - * Return value from 'main'. - */ -static int res; - -/** - * Handle to PSYCstore service. - */ -static struct GNUNET_PSYCSTORE_Handle *h; - -/** - * Handle to PSYCstore operation. - */ -static struct GNUNET_PSYCSTORE_OperationHandle *op; - -/** - * Handle for task for timeout termination. - */ -static struct GNUNET_SCHEDULER_Task *end_badly_task; - -static struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key; -static struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key; - -static struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key; -static struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; - -static struct FragmentClosure -{ - uint8_t n; - uint8_t n_expected; - uint64_t flags[16]; - struct GNUNET_MULTICAST_MessageHeader *msg[16]; -} fcls; - -struct StateClosure { - size_t n; - char *name[16]; - void *value[16]; - size_t value_size[16]; -} scls; - -static struct GNUNET_PSYC_Modifier modifiers[16]; - -/** - * Clean up all resources used. - */ -static void -cleanup () -{ - if (NULL != op) - { - GNUNET_PSYCSTORE_operation_cancel (op); - op = NULL; - } - if (NULL != h) - { - GNUNET_PSYCSTORE_disconnect (h); - h = NULL; - } - if (NULL != channel_key) - { - GNUNET_free (channel_key); - channel_key = NULL; - } - if (NULL != slave_key) - { - GNUNET_free (slave_key); - slave_key = NULL; - } - GNUNET_SCHEDULER_shutdown (); -} - - -/** - * Terminate the testcase (failure). - * - * @param cls NULL - */ -static void -end_badly (void *cls) -{ - res = 1; - cleanup (); -} - - -/** - * Terminate the testcase (success). - * - * @param cls NULL - */ -static void -end_normally (void *cls) -{ - res = 0; - cleanup (); -} - - -/** - * Finish the testcase (successfully). - */ -static void -end () -{ - if (NULL != end_badly_task) - { - GNUNET_SCHEDULER_cancel (end_badly_task); - end_badly_task = NULL; - } - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, - &end_normally, NULL); -} - - -static void -state_reset_result (void *cls, - int64_t result, - const char *err_msg, - uint16_t err_msg_size) -{ - op = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "state_reset_result:\t%d\n", - (int) result); - GNUNET_assert (GNUNET_OK == result); - - op = GNUNET_PSYCSTORE_state_reset (h, &channel_pub_key, - &state_reset_result, cls); - GNUNET_PSYCSTORE_operation_cancel (op); - op = NULL; - end (); -} - - -static int -state_result (void *cls, - const char *name, - const void *value, - uint32_t value_size) -{ - struct StateClosure *scls = cls; - const char *nam = scls->name[scls->n]; - const void *val = scls->value[scls->n]; - size_t val_size = scls->value_size[scls->n++]; - - if (value_size == val_size - && 0 == memcmp (value, val, val_size) - && 0 == strcmp (name, nam)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - " variable %s matches\n", - name); - return GNUNET_YES; - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - " variable %s differs\nReceived: %.*s\nExpected: %.*s\n", - name, (int) value_size, (char*) value, (int) val_size, (char*) val); - GNUNET_assert (0); - return GNUNET_SYSERR; - } -} - - -static void -state_get_prefix_result (void *cls, int64_t result, - const char *err_msg, uint16_t err_msg_size) -{ - struct StateClosure *scls = cls; - op = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "state_get_prefix_result:\t%ld\n", (long int) result); - GNUNET_assert (GNUNET_OK == result && 2 == scls->n); - - op = GNUNET_PSYCSTORE_state_reset (h, &channel_pub_key, - &state_reset_result, cls); -} - - -static void -state_get_result (void *cls, int64_t result, - const char *err_msg, uint16_t err_msg_size) -{ - op = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "state_get_result:\t%ld\n", (long int) result); - GNUNET_assert (GNUNET_OK == result); - - scls.n = 0; - - scls.name[0] = "_sync_bar"; - scls.value[0] = "ten eleven twelve"; - scls.value_size[0] = sizeof ("ten eleven twelve") - 1; - - scls.name[1] = "_sync_foo"; - scls.value[1] = "three two one"; - scls.value_size[1] = sizeof ("three two one") - 1; - - op = GNUNET_PSYCSTORE_state_get_prefix (h, &channel_pub_key, "_sync", - &state_result, - &state_get_prefix_result, &scls); -} - - -static void -counters_result (void *cls, int status, uint64_t max_fragment_id, - uint64_t max_message_id, uint64_t max_group_generation, - uint64_t max_state_message_id) -{ - struct FragmentClosure *fcls = cls; - int result = 0; - op = NULL; - - if (GNUNET_OK == status - && max_fragment_id == GNUNET_ntohll (fcls->msg[2]->fragment_id) - && max_message_id == GNUNET_ntohll (fcls->msg[2]->message_id) - && max_group_generation == GNUNET_ntohll (fcls->msg[2]->group_generation) - && max_state_message_id == GNUNET_ntohll (fcls->msg[0]->message_id)) - result = 1; - - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "counters_get:\t%d\n", result); - GNUNET_assert (result == 1); - - scls.n = 0; - scls.name[0] = "_sync_bar"; - scls.value[0] = "ten eleven twelve"; - scls.value_size[0] = sizeof ("ten eleven twelve") - 1; - - op = GNUNET_PSYCSTORE_state_get (h, &channel_pub_key, "_sync_bar_x_yy_zzz", - &state_result, &state_get_result, &scls); -} - - -static void -state_modify_result (void *cls, int64_t result, - const char *err_msg, uint16_t err_msg_size) -{ - op = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "state_modify_result:\t%ld\n", (long int) result); - GNUNET_assert (GNUNET_OK == result); - - op = GNUNET_PSYCSTORE_counters_get (h, &channel_pub_key, - &counters_result, cls); -} - - -static void -state_sync_result (void *cls, int64_t result, - const char *err_msg, uint16_t err_msg_size) -{ - struct FragmentClosure *fcls = cls; - op = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "state_sync_result:\t%ld\n", (long int) result); - GNUNET_assert (GNUNET_OK == result); - - op = GNUNET_PSYCSTORE_state_modify (h, &channel_pub_key, - GNUNET_ntohll (fcls->msg[0]->message_id), - 0, state_modify_result, fcls); -} - - -static int -fragment_result (void *cls, - struct GNUNET_MULTICAST_MessageHeader *msg, - enum GNUNET_PSYCSTORE_MessageFlags flags) -{ - struct FragmentClosure *fcls = cls; - GNUNET_assert (fcls->n < fcls->n_expected); - struct GNUNET_MULTICAST_MessageHeader *msg0 = fcls->msg[fcls->n]; - uint64_t flags0 = fcls->flags[fcls->n++]; - - if (flags == flags0 && msg->header.size == msg0->header.size - && 0 == memcmp (msg, msg0, ntohs (msg->header.size))) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " fragment %" PRIu64 " matches\n", - GNUNET_ntohll (msg->fragment_id)); - return GNUNET_YES; - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - " fragment differs: expected %" PRIu64 ", got %" PRIu64 "\n", - GNUNET_ntohll (msg0->fragment_id), - GNUNET_ntohll (msg->fragment_id)); - GNUNET_assert (0); - return GNUNET_SYSERR; - } -} - - -static void -message_get_latest_result (void *cls, int64_t result, - const char *err_msg, uint16_t err_msg_size) -{ - struct FragmentClosure *fcls = cls; - op = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "message_get_latest:\t%ld\n", (long int) result); - GNUNET_assert (0 < result && fcls->n == fcls->n_expected); - - modifiers[0] = (struct GNUNET_PSYC_Modifier) { - .oper = '=', - .name = "_sync_foo", - .value = "three two one", - .value_size = sizeof ("three two one") - 1 - }; - modifiers[1] = (struct GNUNET_PSYC_Modifier) { - .oper = '=', - .name = "_sync_bar", - .value = "ten eleven twelve", - .value_size = sizeof ("ten eleven twelve") - 1 - }; - - op = GNUNET_PSYCSTORE_state_sync (h, &channel_pub_key, - GNUNET_ntohll (fcls->msg[0]->message_id) + 1, - GNUNET_ntohll (fcls->msg[0]->message_id) + 2, - 2, modifiers, state_sync_result, fcls); -} - - -static void -message_get_result (void *cls, int64_t result, - const char *err_msg, uint16_t err_msg_size) -{ - struct FragmentClosure *fcls = cls; - op = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "message_get:\t%ld\n", (long int) result); - GNUNET_assert (0 < result && fcls->n == fcls->n_expected); - - fcls->n = 0; - fcls->n_expected = 3; - op = GNUNET_PSYCSTORE_message_get_latest (h, &channel_pub_key, &slave_pub_key, - 1, "", &fragment_result, - &message_get_latest_result, fcls); -} - - -static void -message_get_fragment_result (void *cls, int64_t result, - const char *err_msg, uint16_t err_msg_size) -{ - struct FragmentClosure *fcls = cls; - op = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "message_get_fragment:\t%ld\n", (long int) result); - GNUNET_assert (0 < result && fcls->n == fcls->n_expected); - - fcls->n = 0; - fcls->n_expected = 3; - uint64_t message_id = GNUNET_ntohll (fcls->msg[0]->message_id); - op = GNUNET_PSYCSTORE_message_get (h, &channel_pub_key, &slave_pub_key, - message_id, message_id, 0, "", - &fragment_result, - &message_get_result, fcls); -} - - -static void -fragment_get_latest_result (void *cls, int64_t result, - const char *err_msg, uint16_t err_msg_size) -{ - struct FragmentClosure *fcls = cls; - op = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "fragment_get_latest:\t%ld\n", (long int) result); - GNUNET_assert (0 < result && fcls->n == fcls->n_expected); - - fcls->n = 1; - fcls->n_expected = 2; - op = GNUNET_PSYCSTORE_message_get_fragment (h, &channel_pub_key, &slave_pub_key, - GNUNET_ntohll (fcls->msg[1]->message_id), - GNUNET_ntohll (fcls->msg[1]->fragment_offset), - &fragment_result, - &message_get_fragment_result, fcls); -} - - -static void -fragment_get_result (void *cls, int64_t result, - const char *err_msg, uint16_t err_msg_size) -{ - struct FragmentClosure *fcls = cls; - op = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "fragment_get:\t%d\n", - (int) result); - GNUNET_assert (0 < result && fcls->n == fcls->n_expected); - - fcls->n = 0; - fcls->n_expected = 3; - op = GNUNET_PSYCSTORE_fragment_get_latest (h, &channel_pub_key, - &slave_pub_key, fcls->n_expected, - &fragment_result, - &fragment_get_latest_result, fcls); -} - - -static void -fragment_store_result (void *cls, int64_t result, - const char *err_msg, uint16_t err_msg_size) -{ - op = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "fragment_store:\t%ld\n", (long int) result); - GNUNET_assert (GNUNET_OK == result); - - if ((intptr_t) cls == GNUNET_YES) - { /* last fragment */ - fcls.n = 0; - fcls.n_expected = 1; - uint64_t fragment_id = GNUNET_ntohll (fcls.msg[0]->fragment_id); - op = GNUNET_PSYCSTORE_fragment_get (h, &channel_pub_key, &slave_pub_key, - fragment_id, fragment_id, - &fragment_result, - &fragment_get_result, &fcls); - } -} - - -static void -fragment_store () -{ - struct GNUNET_MULTICAST_MessageHeader *msg; - fcls.flags[0] = GNUNET_PSYCSTORE_MESSAGE_STATE; - fcls.msg[0] = msg = GNUNET_malloc (sizeof (*msg) + sizeof (channel_pub_key)); - GNUNET_assert (msg != NULL); - - msg->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE); - msg->header.size = htons (sizeof (*msg) + sizeof (channel_pub_key)); - - msg->hop_counter = htonl (9); - msg->fragment_id = GNUNET_htonll (INT64_MAX - 8); - msg->fragment_offset = GNUNET_htonll (0); - msg->message_id = GNUNET_htonll (INT64_MAX - 10); - msg->group_generation = GNUNET_htonll (INT64_MAX - 3); - msg->flags = htonl (GNUNET_MULTICAST_MESSAGE_LAST_FRAGMENT); - - GNUNET_memcpy (&msg[1], &channel_pub_key, sizeof (channel_pub_key)); - - msg->purpose.size = htonl (ntohs (msg->header.size) - - sizeof (msg->header) - - sizeof (msg->hop_counter) - - sizeof (msg->signature)); - msg->purpose.purpose = htonl (234); - GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (channel_key, &msg->purpose, - &msg->signature)); - - op = GNUNET_PSYCSTORE_fragment_store (h, &channel_pub_key, msg, fcls.flags[0], - &fragment_store_result, GNUNET_NO); - - fcls.flags[1] = GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED; - fcls.msg[1] = msg = GNUNET_malloc (sizeof (*msg) + sizeof (channel_pub_key)); - GNUNET_memcpy (msg, fcls.msg[0], sizeof (*msg) + sizeof (channel_pub_key)); - msg->fragment_id = GNUNET_htonll (INT64_MAX - 4); - msg->fragment_offset = GNUNET_htonll (1024); - - op = GNUNET_PSYCSTORE_fragment_store (h, &channel_pub_key, msg, fcls.flags[1], - &fragment_store_result, GNUNET_NO); - - fcls.flags[2] = GNUNET_PSYCSTORE_MESSAGE_STATE_HASH; - fcls.msg[2] = msg = GNUNET_malloc (sizeof (*msg) + sizeof (channel_pub_key)); - GNUNET_memcpy (msg, fcls.msg[1], sizeof (*msg) + sizeof (channel_pub_key)); - msg->fragment_id = GNUNET_htonll (INT64_MAX); - msg->fragment_offset = GNUNET_htonll (16384); - - op = GNUNET_PSYCSTORE_fragment_store (h, &channel_pub_key, msg, fcls.flags[2], - &fragment_store_result, (void *) GNUNET_YES); -} - - -static void -membership_test_result (void *cls, int64_t result, - const char *err_msg, uint16_t err_msg_size) -{ - op = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "membership_test:\t%ld\n", (long int) result); - GNUNET_assert (GNUNET_OK == result); - - fragment_store (); -} - - -static void -membership_store_result (void *cls, int64_t result, - const char *err_msg, uint16_t err_msg_size) -{ - op = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "membership_store:\t%ld\n", (long int) result); - GNUNET_assert (GNUNET_OK == result); - - op = GNUNET_PSYCSTORE_membership_test (h, &channel_pub_key, &slave_pub_key, - INT64_MAX - 10, 2, - &membership_test_result, NULL); -} - - -/** - * Main function of the test, run from scheduler. - * - * @param cls NULL - * @param cfg configuration we use (also to connect to PSYCstore service) - * @param peer handle to access more of the peer (not used) - */ -static void -#if DEBUG_TEST_PSYCSTORE -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) -#else -run (void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Peer *peer) -#endif -{ - end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); - - h = GNUNET_PSYCSTORE_connect (cfg); - GNUNET_assert (NULL != h); - - channel_key = GNUNET_CRYPTO_eddsa_key_create (); - slave_key = GNUNET_CRYPTO_ecdsa_key_create (); - - GNUNET_CRYPTO_eddsa_key_get_public (channel_key, &channel_pub_key); - GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key); - - op = GNUNET_PSYCSTORE_membership_store (h, &channel_pub_key, &slave_pub_key, - GNUNET_YES, INT64_MAX - 5, - INT64_MAX - 10, 2, - &membership_store_result, NULL); -} - - -int -main (int argc, char *argv[]) -{ - res = 1; -#if DEBUG_TEST_PSYCSTORE - const struct GNUNET_GETOPT_CommandLineOption opts[] = { - GNUNET_GETOPT_OPTION_END - }; - if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-psycstore", - "test-psycstore [options]", - opts, &run, NULL)) - return 1; -#else - if (0 != GNUNET_TESTING_service_run ("test-psycstore", "psycstore", - "test_psycstore.conf", &run, NULL)) - return 1; -#endif - return res; -} - -/* end of test_psycstore.c */ diff --git a/src/psycstore/test_psycstore.conf b/src/psycstore/test_psycstore.conf deleted file mode 100644 index fa7c2d003..000000000 --- a/src/psycstore/test_psycstore.conf +++ /dev/null @@ -1,8 +0,0 @@ -[PATHS] -GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-psycstore/ - -[psycstore] -DATABASE = sqlite - -[psycstore-sqlite] -FILENAME = $GNUNET_TEST_HOME/psycstore/sqlite.db diff --git a/src/psycutil/.gitignore b/src/psycutil/.gitignore deleted file mode 100644 index 03d8197fb..000000000 --- a/src/psycutil/.gitignore +++ /dev/null @@ -1 +0,0 @@ -test_psyc_env diff --git a/src/psycutil/Makefile.am b/src/psycutil/Makefile.am deleted file mode 100644 index 2732c3a21..000000000 --- a/src/psycutil/Makefile.am +++ /dev/null @@ -1,45 +0,0 @@ -# This Makefile.am is in the public domain -AM_CPPFLAGS = -I$(top_srcdir)/src/include - -pkgcfgdir= $(pkgdatadir)/config.d/ - -libexecdir= $(pkglibdir)/libexec/ - -if MINGW - WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -endif - -if USE_COVERAGE - AM_CFLAGS = --coverage -O0 - XLIB = -lgcov -endif - -lib_LTLIBRARIES = libgnunetpsycutil.la - -libgnunetpsycutil_la_SOURCES = \ - psyc_env.c \ - psyc_message.c \ - psyc_slicer.c -libgnunetpsycutil_la_LIBADD = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(GN_LIBINTL) $(XLIB) -libgnunetpsycutil_la_LDFLAGS = \ - $(GN_LIB_LDFLAGS) $(WINFLAGS) \ - -version-info 0:0:0 - -if HAVE_TESTING -check_PROGRAMS = \ - test_psyc_env -endif - -if ENABLE_TEST_RUN -AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; -TESTS = $(check_PROGRAMS) -endif - -test_psyc_env_SOURCES = \ - test_psyc_env.c -test_psyc_env_LDADD = \ - libgnunetpsycutil.la \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/util/libgnunetutil.la diff --git a/src/psycutil/psyc_env.c b/src/psycutil/psyc_env.c deleted file mode 100644 index fc4b8eb7c..000000000 --- a/src/psycutil/psyc_env.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * This file is part of GNUnet. - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @author Gabor X Toth - * - * @file - * Library providing operations for the @e environment of - * PSYC and Social messages. - */ - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_psyc_env.h" - -/** - * Environment for a message. - * - * Contains modifiers. - */ -struct GNUNET_PSYC_Environment -{ - struct GNUNET_PSYC_Modifier *mod_head; - struct GNUNET_PSYC_Modifier *mod_tail; - size_t mod_count; -}; - - -/** - * Create an environment. - * - * @return A newly allocated environment. - */ -struct GNUNET_PSYC_Environment * -GNUNET_PSYC_env_create () -{ - return GNUNET_new (struct GNUNET_PSYC_Environment); -} - - -/** - * Add a modifier to the environment. - * - * @param env The environment. - * @param oper Operation to perform. - * @param name Name of the variable. - * @param value Value of the variable. - * @param value_size Size of @a value. - */ -void -GNUNET_PSYC_env_add (struct GNUNET_PSYC_Environment *env, - enum GNUNET_PSYC_Operator oper, const char *name, - const void *value, size_t value_size) -{ - struct GNUNET_PSYC_Modifier *mod = GNUNET_new (struct GNUNET_PSYC_Modifier); - mod->oper = oper; - mod->name = name; - mod->value = value; - mod->value_size = value_size; - GNUNET_CONTAINER_DLL_insert_tail (env->mod_head, env->mod_tail, mod); - env->mod_count++; -} - - -/** - * Get the first modifier of the environment. - */ -struct GNUNET_PSYC_Modifier * -GNUNET_PSYC_env_head (const struct GNUNET_PSYC_Environment *env) -{ - return env->mod_head; -} - - -/** - * Get the last modifier of the environment. - */ -struct GNUNET_PSYC_Modifier * -GNUNET_PSYC_env_tail (const struct GNUNET_PSYC_Environment *env) -{ - return env->mod_tail; -} - - -/** - * Remove a modifier from the environment. - */ -void -GNUNET_PSYC_env_remove (struct GNUNET_PSYC_Environment *env, - struct GNUNET_PSYC_Modifier *mod) -{ - GNUNET_CONTAINER_DLL_remove (env->mod_head, env->mod_tail, mod); -} - - -/** - * Get the modifier at the beginning of an environment and remove it. - * - * @param env - * @param oper - * @param name - * @param value - * @param value_size - * - * @return - */ -int -GNUNET_PSYC_env_shift (struct GNUNET_PSYC_Environment *env, - enum GNUNET_PSYC_Operator *oper, const char **name, - const void **value, size_t *value_size) -{ - if (NULL == env->mod_head) - return GNUNET_NO; - - struct GNUNET_PSYC_Modifier *mod = env->mod_head; - *oper = mod->oper; - *name = mod->name; - *value = mod->value; - *value_size = mod->value_size; - - GNUNET_CONTAINER_DLL_remove (env->mod_head, env->mod_tail, mod); - GNUNET_free (mod); - env->mod_count--; - - return GNUNET_YES; -} - - -/** - * Iterate through all modifiers in the environment. - * - * @param env The environment. - * @param it Iterator. - * @param it_cls Closure for iterator. - */ -void -GNUNET_PSYC_env_iterate (const struct GNUNET_PSYC_Environment *env, - GNUNET_PSYC_Iterator it, void *it_cls) -{ - struct GNUNET_PSYC_Modifier *mod; - for (mod = env->mod_head; NULL != mod; mod = mod->next) - it (it_cls, mod->oper, mod->name, mod->value, mod->value_size); -} - - -/** - * Get the number of modifiers in the environment. - * - * @param env The environment. - * - * @return Number of modifiers. - */ -size_t -GNUNET_PSYC_env_get_count (const struct GNUNET_PSYC_Environment *env) -{ - return env->mod_count; -} - - -/** - * Destroy an environment. - * - * @param env The environment to destroy. - */ -void -GNUNET_PSYC_env_destroy (struct GNUNET_PSYC_Environment *env) -{ - struct GNUNET_PSYC_Modifier *mod, *prev = NULL; - for (mod = env->mod_head; NULL != mod; mod = mod->next) - { - if (NULL != prev) - GNUNET_free (prev); - prev = mod; - } - if (NULL != prev) - GNUNET_free (prev); - - GNUNET_free (env); -} diff --git a/src/psycutil/psyc_message.c b/src/psycutil/psyc_message.c deleted file mode 100644 index a03eff47f..000000000 --- a/src/psycutil/psyc_message.c +++ /dev/null @@ -1,1355 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file psycutil/psyc_message.c - * @brief PSYC utilities; receiving/transmitting/logging PSYC messages. - * @author Gabor X Toth - */ - -#include - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_psyc_util_lib.h" -#include "gnunet_psyc_service.h" - -#define LOG(kind,...) GNUNET_log_from (kind, "psyc-util",__VA_ARGS__) - - -struct GNUNET_PSYC_TransmitHandle -{ - /** - * Client connection to service. - */ - struct GNUNET_MQ_Handle *mq; - - /** - * Message currently being received from the client. - */ - struct GNUNET_MessageHeader *msg; - - /** - * Envelope for @a msg - */ - struct GNUNET_MQ_Envelope *env; - - /** - * Callback to request next modifier from client. - */ - GNUNET_PSYC_TransmitNotifyModifier notify_mod; - - /** - * Closure for the notify callbacks. - */ - void *notify_mod_cls; - - /** - * Callback to request next data fragment from client. - */ - GNUNET_PSYC_TransmitNotifyData notify_data; - - /** - * Closure for the notify callbacks. - */ - void *notify_data_cls; - - /** - * Modifier of the environment that is currently being transmitted. - */ - struct GNUNET_PSYC_Modifier *mod; - - /** - * - */ - const char *mod_value; - - /** - * Number of bytes remaining to be transmitted from the current modifier value. - */ - uint32_t mod_value_remaining; - - /** - * State of the current message being received from client. - */ - enum GNUNET_PSYC_MessageState state; - - /** - * Number of PSYC_TRANSMIT_ACK messages we are still waiting for. - */ - uint8_t acks_pending; - - /** - * Is transmission paused? - */ - uint8_t paused; - - /** - * Are we currently transmitting a message? - */ - uint8_t in_transmit; - - /** - * Notify callback is currently being called. - */ - uint8_t in_notify; - -}; - - - -struct GNUNET_PSYC_ReceiveHandle -{ - /** - * Message callback. - */ - GNUNET_PSYC_MessageCallback message_cb; - - /** - * Message part callback. - */ - GNUNET_PSYC_MessagePartCallback message_part_cb; - - /** - * Closure for the callbacks. - */ - void *cb_cls; - - /** - * ID of the message being received from the PSYC service. - */ - uint64_t message_id; - - /** - * Public key of the slave from which a message is being received. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; - - /** - * State of the currently being received message from the PSYC service. - */ - enum GNUNET_PSYC_MessageState state; - - /** - * Flags for the currently being received message from the PSYC service. - */ - enum GNUNET_PSYC_MessageFlags flags; - - /** - * Expected value size for the modifier being received from the PSYC service. - */ - uint32_t mod_value_size_expected; - - /** - * Actual value size for the modifier being received from the PSYC service. - */ - uint32_t mod_value_size; -}; - - -/**** Messages ****/ - - -/** - * Create a PSYC message. - * - * @param method_name - * PSYC method for the message. - * @param env - * Environment for the message. - * @param data - * Data payload for the message. - * @param data_size - * Size of @a data. - * - * @return Message header with size information, - * followed by the message parts. - */ -struct GNUNET_PSYC_Message * -GNUNET_PSYC_message_create (const char *method_name, - const struct GNUNET_PSYC_Environment *env, - const void *data, - size_t data_size) -{ - struct GNUNET_PSYC_Modifier *mod = NULL; - struct GNUNET_PSYC_MessageMethod *pmeth = NULL; - struct GNUNET_PSYC_MessageModifier *pmod = NULL; - struct GNUNET_MessageHeader *pmsg = NULL; - uint16_t env_size = 0; - if (NULL != env) - { - mod = GNUNET_PSYC_env_head (env); - while (NULL != mod) - { - env_size += sizeof (*pmod) + strlen (mod->name) + 1 + mod->value_size; - mod = mod->next; - } - } - - struct GNUNET_PSYC_Message *msg; - uint16_t method_name_size = strlen (method_name) + 1; - if (method_name_size == 1) - return NULL; - - uint16_t msg_size = sizeof (*msg) /* header */ - + sizeof (*pmeth) + method_name_size /* method */ - + env_size /* modifiers */ - + ((0 < data_size) ? sizeof (*pmsg) + data_size : 0) /* data */ - + sizeof (*pmsg); /* end of message */ - msg = GNUNET_malloc (msg_size); - msg->header.size = htons (msg_size); - msg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); /* FIXME */ - - pmeth = (struct GNUNET_PSYC_MessageMethod *) &msg[1]; - pmeth->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD); - pmeth->header.size = htons (sizeof (*pmeth) + method_name_size); - GNUNET_memcpy (&pmeth[1], method_name, method_name_size); - - uint16_t p = sizeof (*msg) + sizeof (*pmeth) + method_name_size; - if (NULL != env) - { - mod = GNUNET_PSYC_env_head (env); - while (NULL != mod) - { - uint16_t mod_name_size = strlen (mod->name) + 1; - pmod = (struct GNUNET_PSYC_MessageModifier *) ((char *) msg + p); - pmod->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER); - pmod->header.size = sizeof (*pmod) + mod_name_size + mod->value_size; - p += pmod->header.size; - pmod->header.size = htons (pmod->header.size); - - pmod->oper = mod->oper; - pmod->name_size = htons (mod_name_size); - pmod->value_size = htonl (mod->value_size); - - GNUNET_memcpy (&pmod[1], mod->name, mod_name_size); - if (0 < mod->value_size) - GNUNET_memcpy ((char *) &pmod[1] + mod_name_size, mod->value, mod->value_size); - - mod = mod->next; - } - } - - if (0 < data_size) - { - pmsg = (struct GNUNET_MessageHeader *) ((char *) msg + p); - pmsg->size = sizeof (*pmsg) + data_size; - p += pmsg->size; - pmsg->size = htons (pmsg->size); - pmsg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA); - GNUNET_memcpy (&pmsg[1], data, data_size); - } - - pmsg = (struct GNUNET_MessageHeader *) ((char *) msg + p); - pmsg->size = htons (sizeof (*pmsg)); - pmsg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END); - - GNUNET_assert (p + sizeof (*pmsg) == msg_size); - return msg; -} - - -void -GNUNET_PSYC_log_message (enum GNUNET_ErrorType kind, - const struct GNUNET_MessageHeader *msg) -{ - uint16_t size = ntohs (msg->size); - uint16_t type = ntohs (msg->type); - - GNUNET_log (kind, - "Message of type %d and size %u:\n", - type, - size); - switch (type) - { - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE: - { - const struct GNUNET_PSYC_MessageHeader *pmsg - = (const struct GNUNET_PSYC_MessageHeader *) msg; - GNUNET_log (kind, - "\tID: %" PRIu64 "\tflags: %x" PRIu32 "\n", - GNUNET_ntohll (pmsg->message_id), - ntohl (pmsg->flags)); - break; - } - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD: - { - const struct GNUNET_PSYC_MessageMethod *meth - = (const struct GNUNET_PSYC_MessageMethod *) msg; - GNUNET_log (kind, - "\t%.*s\n", - (int) (size - sizeof (*meth)), - (const char *) &meth[1]); - break; - } - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: - { - const struct GNUNET_PSYC_MessageModifier *mod - = (const struct GNUNET_PSYC_MessageModifier *) msg; - uint16_t name_size = ntohs (mod->name_size); - char oper = ' ' < mod->oper ? mod->oper : ' '; - GNUNET_log (kind, - "\t%c%.*s\t%.*s\n", - oper, - (int) name_size, - (const char *) &mod[1], - (int) (size - sizeof (*mod) - name_size), - ((const char *) &mod[1]) + name_size); - break; - } - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA: - GNUNET_log (kind, - "\t%.*s\n", - (int) (size - sizeof (*msg)), - (const char *) &msg[1]); - break; - } -} - - -/**** Transmitting messages ****/ - - -/** - * Create a transmission handle. - */ -struct GNUNET_PSYC_TransmitHandle * -GNUNET_PSYC_transmit_create (struct GNUNET_MQ_Handle *mq) -{ - struct GNUNET_PSYC_TransmitHandle *tmit = GNUNET_new (struct GNUNET_PSYC_TransmitHandle); - - tmit->mq = mq; - return tmit; -} - - -/** - * Destroy a transmission handle. - */ -void -GNUNET_PSYC_transmit_destroy (struct GNUNET_PSYC_TransmitHandle *tmit) -{ - GNUNET_free (tmit); -} - - -/** - * Queue a message part for transmission. - * - * The message part is added to the current message buffer. - * When this buffer is full, it is added to the transmission queue. - * - * @param tmit - * Transmission handle. - * @param msg - * Message part, or NULL. - * @param tmit_now - * Transmit message now, or wait for buffer to fill up? - * #GNUNET_YES or #GNUNET_NO. - */ -static void -transmit_queue_insert (struct GNUNET_PSYC_TransmitHandle *tmit, - const struct GNUNET_MessageHeader *msg, - uint8_t tmit_now) -{ - uint16_t size = (NULL != msg) ? ntohs (msg->size) : 0; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Queueing message part of type %u and size %u (tmit_now: %u)).\n", - NULL != msg ? ntohs (msg->type) : 0, size, tmit_now); - - if (NULL != tmit->msg) - { - if (NULL == msg - || GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < tmit->msg->size + size) - { - /* End of message or buffer is full, add it to transmission queue - * and start with empty buffer */ - tmit->msg->size = htons (tmit->msg->size); - GNUNET_MQ_send (tmit->mq, tmit->env); - tmit->env = NULL; - tmit->msg = NULL; - tmit->acks_pending++; - } - else - { - /* Message fits in current buffer, append */ - GNUNET_memcpy ((char *) tmit->msg + tmit->msg->size, msg, size); - tmit->msg->size += size; - } - } - - if (NULL == tmit->msg && NULL != msg) - { - /* Empty buffer, copy over message. */ - tmit->env = GNUNET_MQ_msg_extra (tmit->msg, - GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD, - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); - /* store current message size in host byte order - * then later switch it to network byte order before sending */ - tmit->msg->size = sizeof (*tmit->msg) + size; - - GNUNET_memcpy (&tmit->msg[1], msg, size); - } - - if (NULL != tmit->msg - && (GNUNET_YES == tmit_now - || (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD - < tmit->msg->size + sizeof (struct GNUNET_MessageHeader)))) - { - /* End of message or buffer is full, add it to transmission queue. */ - tmit->msg->size = htons (tmit->msg->size); - GNUNET_MQ_send (tmit->mq, tmit->env); - tmit->env = NULL; - tmit->msg = NULL; - tmit->acks_pending++; - } -} - - -/** - * Request data from client to transmit. - * - * @param tmit Transmission handle. - */ -static void -transmit_data (struct GNUNET_PSYC_TransmitHandle *tmit) -{ - int notify_ret = GNUNET_YES; - uint16_t data_size = 0; - char data[GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD] = ""; - struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) data; - msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA); - - if (NULL != tmit->notify_data) - { - data_size = GNUNET_PSYC_DATA_MAX_PAYLOAD; - tmit->in_notify = GNUNET_YES; - notify_ret = tmit->notify_data (tmit->notify_data_cls, &data_size, &msg[1]); - tmit->in_notify = GNUNET_NO; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, - "transmit_data (ret: %d, size: %u): %.*s\n", - notify_ret, data_size, data_size, &msg[1]); - switch (notify_ret) - { - case GNUNET_NO: - if (0 == data_size) - { - /* Transmission paused, nothing to send. */ - tmit->paused = GNUNET_YES; - return; - } - break; - - case GNUNET_YES: - tmit->state = GNUNET_PSYC_MESSAGE_STATE_END; - break; - - default: - LOG (GNUNET_ERROR_TYPE_ERROR, - "TransmitNotifyData callback returned error when requesting data.\n"); - - tmit->state = GNUNET_PSYC_MESSAGE_STATE_CANCEL; - msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL); - msg->size = htons (sizeof (*msg)); - transmit_queue_insert (tmit, msg, GNUNET_YES); - tmit->in_transmit = GNUNET_NO; - return; - } - - if (0 < data_size) - { - GNUNET_assert (data_size <= GNUNET_PSYC_DATA_MAX_PAYLOAD); - msg->size = htons (sizeof (*msg) + data_size); - transmit_queue_insert (tmit, msg, !notify_ret); - } - - /* End of message. */ - if (GNUNET_YES == notify_ret) - { - msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END); - msg->size = htons (sizeof (*msg)); - transmit_queue_insert (tmit, msg, GNUNET_YES); - /* FIXME: wait for ACK before setting in_transmit to no */ - tmit->in_transmit = GNUNET_NO; - } -} - - -/** - * Request a modifier from a client to transmit. - * - * @param tmit Transmission handle. - */ -static void -transmit_mod (struct GNUNET_PSYC_TransmitHandle *tmit) -{ - uint16_t max_data_size = 0; - uint16_t data_size = 0; - char data[GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD] = ""; - struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) data; - int notify_ret = GNUNET_YES; - - switch (tmit->state) - { - case GNUNET_PSYC_MESSAGE_STATE_MODIFIER: - { - struct GNUNET_PSYC_MessageModifier *mod - = (struct GNUNET_PSYC_MessageModifier *) msg; - msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER); - msg->size = sizeof (struct GNUNET_PSYC_MessageModifier); - - if (NULL != tmit->notify_mod) - { - max_data_size = GNUNET_PSYC_MODIFIER_MAX_PAYLOAD; - data_size = max_data_size; - tmit->in_notify = GNUNET_YES; - notify_ret = tmit->notify_mod (tmit->notify_mod_cls, &data_size, &mod[1], - &mod->oper, &mod->value_size); - tmit->in_notify = GNUNET_NO; - } - - mod->name_size = strnlen ((char *) &mod[1], data_size) + 1; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "transmit_mod (ret: %d, size: %u + %u): %.*s\n", - notify_ret, mod->name_size, mod->value_size, data_size, &mod[1]); - if (mod->name_size < data_size) - { - tmit->mod_value_remaining - = mod->value_size - (data_size - mod->name_size); - mod->value_size = htonl (mod->value_size); - mod->name_size = htons (mod->name_size); - } - else if (0 < data_size) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got invalid modifier name.\n"); - notify_ret = GNUNET_SYSERR; - } - break; - } - case GNUNET_PSYC_MESSAGE_STATE_MOD_CONT: - { - msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT); - msg->size = sizeof (struct GNUNET_MessageHeader); - - if (NULL != tmit->notify_mod) - { - max_data_size = GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD; - data_size = max_data_size; - tmit->in_notify = GNUNET_YES; - notify_ret = tmit->notify_mod (tmit->notify_mod_cls, - &data_size, &msg[1], NULL, NULL); - tmit->in_notify = GNUNET_NO; - } - tmit->mod_value_remaining -= data_size; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "transmit_mod (ret: %d, size: %u): %.*s\n", - notify_ret, data_size, data_size, &msg[1]); - break; - } - default: - GNUNET_assert (0); - } - - switch (notify_ret) - { - case GNUNET_NO: - if (0 == data_size) - { /* Transmission paused, nothing to send. */ - tmit->paused = GNUNET_YES; - return; - } - tmit->state - = (0 == tmit->mod_value_remaining) - ? GNUNET_PSYC_MESSAGE_STATE_MODIFIER - : GNUNET_PSYC_MESSAGE_STATE_MOD_CONT; - break; - - case GNUNET_YES: /* End of modifiers. */ - GNUNET_assert (0 == tmit->mod_value_remaining); - break; - - default: - LOG (GNUNET_ERROR_TYPE_ERROR, - "TransmitNotifyModifier callback returned with error.\n"); - - tmit->state = GNUNET_PSYC_MESSAGE_STATE_CANCEL; - msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL); - msg->size = htons (sizeof (*msg)); - transmit_queue_insert (tmit, msg, GNUNET_YES); - tmit->in_transmit = GNUNET_NO; - return; - } - - if (0 < data_size) - { - GNUNET_assert (data_size <= max_data_size); - msg->size = htons (msg->size + data_size); - transmit_queue_insert (tmit, msg, GNUNET_NO); - } - - if (GNUNET_YES == notify_ret) - { - tmit->state = GNUNET_PSYC_MESSAGE_STATE_DATA; - if (0 == tmit->acks_pending) - transmit_data (tmit); - } - else - { - transmit_mod (tmit); - } -} - - -int -transmit_notify_env (void *cls, uint16_t *data_size, void *data, uint8_t *oper, - uint32_t *full_value_size) - -{ - struct GNUNET_PSYC_TransmitHandle *tmit = cls; - uint16_t name_size = 0; - uint32_t value_size = 0; - const char *value = NULL; - - if (NULL != oper) - { /* New modifier */ - if (NULL != tmit->mod) - tmit->mod = tmit->mod->next; - if (NULL == tmit->mod) - { /* No more modifiers, continue with data */ - *data_size = 0; - return GNUNET_YES; - } - - GNUNET_assert (tmit->mod->value_size < UINT32_MAX); - *full_value_size = tmit->mod->value_size; - *oper = tmit->mod->oper; - name_size = strlen (tmit->mod->name) + 1; - - if (name_size + tmit->mod->value_size <= *data_size) - { - value_size = tmit->mod->value_size; - *data_size = name_size + value_size; - } - else /* full modifier does not fit in data, continuation needed */ - { - value_size = *data_size - name_size; - tmit->mod_value = tmit->mod->value + value_size; - } - - GNUNET_memcpy (data, tmit->mod->name, name_size); - GNUNET_memcpy ((char *)data + name_size, tmit->mod->value, value_size); - return GNUNET_NO; - } - else - { /* Modifier continuation */ - GNUNET_assert (NULL != tmit->mod_value && 0 < tmit->mod_value_remaining); - value = tmit->mod_value; - if (tmit->mod_value_remaining <= *data_size) - { - value_size = tmit->mod_value_remaining; - tmit->mod_value = NULL; - } - else - { - value_size = *data_size; - tmit->mod_value += value_size; - } - - if (*data_size < value_size) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Value in environment larger than buffer: %u < %zu\n", - *data_size, value_size); - *data_size = 0; - return GNUNET_NO; - } - - *data_size = value_size; - GNUNET_memcpy (data, value, value_size); - return (NULL == tmit->mod_value) ? GNUNET_YES : GNUNET_NO; - } -} - - -/** - * Transmit a message. - * - * @param tmit - * Transmission handle. - * @param method_name - * Which method should be invoked. - * @param env - * Environment for the message. - * Should stay available until the first call to notify_data. - * Can be NULL if there are no modifiers or @a notify_mod is - * provided instead. - * @param notify_mod - * Function to call to obtain modifiers. - * Can be NULL if there are no modifiers or @a env is provided instead. - * @param notify_data - * Function to call to obtain fragments of the data. - * @param notify_cls - * Closure for @a notify_mod and @a notify_data. - * @param flags - * Flags for the message being transmitted. - * - * @return #GNUNET_OK if the transmission was started. - * #GNUNET_SYSERR if another transmission is already going on. - */ -int -GNUNET_PSYC_transmit_message (struct GNUNET_PSYC_TransmitHandle *tmit, - const char *method_name, - const struct GNUNET_PSYC_Environment *env, - GNUNET_PSYC_TransmitNotifyModifier notify_mod, - GNUNET_PSYC_TransmitNotifyData notify_data, - void *notify_cls, - uint32_t flags) -{ - if (GNUNET_NO != tmit->in_transmit) - return GNUNET_SYSERR; - tmit->in_transmit = GNUNET_YES; - - size_t size = strlen (method_name) + 1; - struct GNUNET_PSYC_MessageMethod *pmeth; - - tmit->env = GNUNET_MQ_msg_extra (tmit->msg, - GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD, - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); - /* store current message size in host byte order - * then later switch it to network byte order before sending */ - tmit->msg->size = sizeof (*tmit->msg) + sizeof (*pmeth) + size; - - if (NULL != notify_mod) - { - tmit->notify_mod = notify_mod; - tmit->notify_mod_cls = notify_cls; - } - else - { - tmit->notify_mod = &transmit_notify_env; - tmit->notify_mod_cls = tmit; - if (NULL != env) - { - struct GNUNET_PSYC_Modifier mod = {}; - mod.next = GNUNET_PSYC_env_head (env); - tmit->mod = &mod; - - struct GNUNET_PSYC_Modifier *m = tmit->mod; - while (NULL != (m = m->next)) - { - if (m->oper != GNUNET_PSYC_OP_SET) - flags |= GNUNET_PSYC_MASTER_TRANSMIT_STATE_MODIFY; - } - } - else - { - tmit->mod = NULL; - } - } - - pmeth = (struct GNUNET_PSYC_MessageMethod *) &tmit->msg[1]; - pmeth->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD); - pmeth->header.size = htons (sizeof (*pmeth) + size); - pmeth->flags = htonl (flags); - GNUNET_memcpy (&pmeth[1], method_name, size); - - tmit->state = GNUNET_PSYC_MESSAGE_STATE_MODIFIER; - tmit->notify_data = notify_data; - tmit->notify_data_cls = notify_cls; - - transmit_mod (tmit); - return GNUNET_OK; -} - - -/** - * Resume transmission. - * - * @param tmit Transmission handle. - */ -void -GNUNET_PSYC_transmit_resume (struct GNUNET_PSYC_TransmitHandle *tmit) -{ - if (GNUNET_YES != tmit->in_transmit || GNUNET_NO != tmit->in_notify) - return; - - if (0 == tmit->acks_pending) - { - tmit->paused = GNUNET_NO; - transmit_data (tmit); - } -} - - -/** - * Abort transmission request. - * - * @param tmit Transmission handle. - */ -void -GNUNET_PSYC_transmit_cancel (struct GNUNET_PSYC_TransmitHandle *tmit) -{ - if (GNUNET_NO == tmit->in_transmit) - return; - - tmit->state = GNUNET_PSYC_MESSAGE_STATE_CANCEL; - tmit->in_transmit = GNUNET_NO; - tmit->paused = GNUNET_NO; - - /* FIXME */ - struct GNUNET_MessageHeader msg; - msg.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL); - msg.size = htons (sizeof (msg)); - transmit_queue_insert (tmit, &msg, GNUNET_YES); -} - - -/** - * Got acknowledgement of a transmitted message part, continue transmission. - * - * @param tmit Transmission handle. - */ -void -GNUNET_PSYC_transmit_got_ack (struct GNUNET_PSYC_TransmitHandle *tmit) -{ - if (0 == tmit->acks_pending) - { - LOG (GNUNET_ERROR_TYPE_WARNING, "Ignoring extraneous message ACK\n"); - GNUNET_break (0); - return; - } - tmit->acks_pending--; - - if (GNUNET_YES == tmit->paused) - return; - - switch (tmit->state) - { - case GNUNET_PSYC_MESSAGE_STATE_MODIFIER: - case GNUNET_PSYC_MESSAGE_STATE_MOD_CONT: - transmit_mod (tmit); - break; - - case GNUNET_PSYC_MESSAGE_STATE_DATA: - transmit_data (tmit); - break; - - case GNUNET_PSYC_MESSAGE_STATE_END: - case GNUNET_PSYC_MESSAGE_STATE_CANCEL: - break; - - default: - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Ignoring message ACK in state %u.\n", tmit->state); - } -} - - -/**** Receiving messages ****/ - - -/** - * Create handle for receiving messages. - */ -struct GNUNET_PSYC_ReceiveHandle * -GNUNET_PSYC_receive_create (GNUNET_PSYC_MessageCallback message_cb, - GNUNET_PSYC_MessagePartCallback message_part_cb, - void *cb_cls) -{ - struct GNUNET_PSYC_ReceiveHandle *recv = GNUNET_malloc (sizeof (*recv)); - recv->message_cb = message_cb; - recv->message_part_cb = message_part_cb; - recv->cb_cls = cb_cls; - return recv; -} - - -/** - * Destroy handle for receiving messages. - */ -void -GNUNET_PSYC_receive_destroy (struct GNUNET_PSYC_ReceiveHandle *recv) -{ - GNUNET_free (recv); -} - - -/** - * Reset stored data related to the last received message. - */ -void -GNUNET_PSYC_receive_reset (struct GNUNET_PSYC_ReceiveHandle *recv) -{ - recv->state = GNUNET_PSYC_MESSAGE_STATE_START; - recv->flags = 0; - recv->message_id = 0; - recv->mod_value_size = 0; - recv->mod_value_size_expected = 0; -} - - -static void -recv_error (struct GNUNET_PSYC_ReceiveHandle *recv) -{ - if (NULL != recv->message_part_cb) - recv->message_part_cb (recv->cb_cls, NULL, NULL); - - if (NULL != recv->message_cb) - recv->message_cb (recv->cb_cls, NULL); - - GNUNET_PSYC_receive_reset (recv); -} - - -/** - * Handle incoming PSYC message. - * - * @param recv Receive handle. - * @param msg The message. - * - * @return #GNUNET_OK on success, - * #GNUNET_SYSERR on receive error. - */ -int -GNUNET_PSYC_receive_message (struct GNUNET_PSYC_ReceiveHandle *recv, - const struct GNUNET_PSYC_MessageHeader *msg) -{ - uint16_t size = ntohs (msg->header.size); - uint32_t flags = ntohl (msg->flags); - - GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, - (struct GNUNET_MessageHeader *) msg); - - if (GNUNET_PSYC_MESSAGE_STATE_START == recv->state) - { - recv->message_id = GNUNET_ntohll (msg->message_id); - recv->flags = flags; - recv->slave_pub_key = msg->slave_pub_key; - recv->mod_value_size = 0; - recv->mod_value_size_expected = 0; - } - else if (GNUNET_ntohll (msg->message_id) != recv->message_id) - { - // FIXME - LOG (GNUNET_ERROR_TYPE_WARNING, - "Unexpected message ID. Got: %" PRIu64 ", expected: %" PRIu64 "\n", - GNUNET_ntohll (msg->message_id), recv->message_id); - GNUNET_break_op (0); - recv_error (recv); - return GNUNET_SYSERR; - } - else if (flags != recv->flags) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - "Unexpected message flags. Got: %lu, expected: %lu\n", - flags, recv->flags); - GNUNET_break_op (0); - recv_error (recv); - return GNUNET_SYSERR; - } - - uint16_t pos = 0, psize = 0, ptype, size_eq, size_min; - - for (pos = 0; sizeof (*msg) + pos < size; pos += psize) - { - const struct GNUNET_MessageHeader *pmsg - = (const struct GNUNET_MessageHeader *) ((char *) &msg[1] + pos); - psize = ntohs (pmsg->size); - ptype = ntohs (pmsg->type); - size_eq = size_min = 0; - - if (psize < sizeof (*pmsg) || sizeof (*msg) + pos + psize > size) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Dropping message of type %u with invalid size %u.\n", - ptype, psize); - recv_error (recv); - return GNUNET_SYSERR; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received message part of type %u and size %u from PSYC.\n", - ptype, psize); - GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg); - - switch (ptype) - { - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD: - size_min = sizeof (struct GNUNET_PSYC_MessageMethod); - break; - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: - size_min = sizeof (struct GNUNET_PSYC_MessageModifier); - break; - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA: - size_min = sizeof (struct GNUNET_MessageHeader); - break; - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL: - size_eq = sizeof (struct GNUNET_MessageHeader); - break; - default: - GNUNET_break_op (0); - recv_error (recv); - return GNUNET_SYSERR; - } - - if (! ((0 < size_eq && psize == size_eq) - || (0 < size_min && size_min <= psize))) - { - GNUNET_break_op (0); - recv_error (recv); - return GNUNET_SYSERR; - } - - switch (ptype) - { - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD: - { - struct GNUNET_PSYC_MessageMethod *meth - = (struct GNUNET_PSYC_MessageMethod *) pmsg; - - if (GNUNET_PSYC_MESSAGE_STATE_START != recv->state) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - "Dropping out of order message method (%u).\n", - recv->state); - /* It is normal to receive an incomplete message right after connecting, - * but should not happen later. - * FIXME: add a check for this condition. - */ - GNUNET_break_op (0); - recv_error (recv); - return GNUNET_SYSERR; - } - - if ('\0' != *((char *) meth + psize - 1)) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - "Dropping message with malformed method. " - "Message ID: %" PRIu64 "\n", recv->message_id); - GNUNET_break_op (0); - recv_error (recv); - return GNUNET_SYSERR; - } - recv->state = GNUNET_PSYC_MESSAGE_STATE_METHOD; - break; - } - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: - { - if (!(GNUNET_PSYC_MESSAGE_STATE_METHOD == recv->state - || GNUNET_PSYC_MESSAGE_STATE_MODIFIER == recv->state - || GNUNET_PSYC_MESSAGE_STATE_MOD_CONT == recv->state)) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - "Dropping out of order message modifier (%u).\n", - recv->state); - GNUNET_break_op (0); - recv_error (recv); - return GNUNET_SYSERR; - } - - struct GNUNET_PSYC_MessageModifier *mod - = (struct GNUNET_PSYC_MessageModifier *) pmsg; - - uint16_t name_size = ntohs (mod->name_size); - recv->mod_value_size_expected = ntohl (mod->value_size); - recv->mod_value_size = psize - sizeof (*mod) - name_size; - - if (psize < sizeof (*mod) + name_size - || '\0' != *((char *) &mod[1] + name_size - 1) - || recv->mod_value_size_expected < recv->mod_value_size) - { - LOG (GNUNET_ERROR_TYPE_WARNING, "Dropping malformed modifier.\n"); - GNUNET_break_op (0); - recv_error (recv); - return GNUNET_SYSERR; - } - recv->state = GNUNET_PSYC_MESSAGE_STATE_MODIFIER; - break; - } - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: - { - recv->mod_value_size += psize - sizeof (*pmsg); - - if (!(GNUNET_PSYC_MESSAGE_STATE_MODIFIER == recv->state - || GNUNET_PSYC_MESSAGE_STATE_MOD_CONT == recv->state) - || recv->mod_value_size_expected < recv->mod_value_size) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - "Dropping out of order message modifier continuation " - "!(%u == %u || %u == %u) || %lu < %lu.\n", - GNUNET_PSYC_MESSAGE_STATE_MODIFIER, recv->state, - GNUNET_PSYC_MESSAGE_STATE_MOD_CONT, recv->state, - recv->mod_value_size_expected, recv->mod_value_size); - GNUNET_break_op (0); - recv_error (recv); - return GNUNET_SYSERR; - } - break; - } - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA: - { - if (recv->state < GNUNET_PSYC_MESSAGE_STATE_METHOD - || recv->mod_value_size_expected != recv->mod_value_size) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - "Dropping out of order message data fragment " - "(%u < %u || %lu != %lu).\n", - recv->state, GNUNET_PSYC_MESSAGE_STATE_METHOD, - recv->mod_value_size_expected, recv->mod_value_size); - - GNUNET_break_op (0); - recv_error (recv); - return GNUNET_SYSERR; - } - recv->state = GNUNET_PSYC_MESSAGE_STATE_DATA; - break; - } - } - - if (NULL != recv->message_part_cb) - recv->message_part_cb (recv->cb_cls, msg, pmsg); - - switch (ptype) - { - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL: - GNUNET_PSYC_receive_reset (recv); - break; - } - } - - if (NULL != recv->message_cb) - recv->message_cb (recv->cb_cls, msg); - return GNUNET_OK; -} - - -/** - * Check if @a data contains a series of valid message parts. - * - * @param data_size Size of @a data. - * @param data Data. - * @param[out] first_ptype Type of first message part. - * @param[out] last_ptype Type of last message part. - * - * @return Number of message parts found in @a data. - * or GNUNET_SYSERR if the message contains invalid parts. - */ -int -GNUNET_PSYC_receive_check_parts (uint16_t data_size, const char *data, - uint16_t *first_ptype, uint16_t *last_ptype) -{ - const struct GNUNET_MessageHeader *pmsg; - uint16_t parts = 0, ptype = 0, psize = 0, pos = 0; - if (NULL != first_ptype) - *first_ptype = 0; - if (NULL != last_ptype) - *last_ptype = 0; - - for (pos = 0; pos < data_size; pos += psize, parts++) - { - pmsg = (const struct GNUNET_MessageHeader *) (data + pos); - GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg); - psize = ntohs (pmsg->size); - ptype = ntohs (pmsg->type); - if (0 == parts && NULL != first_ptype) - *first_ptype = ptype; - if (NULL != last_ptype - && *last_ptype < GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END) - *last_ptype = ptype; - if (psize < sizeof (*pmsg) - || pos + psize > data_size - || ptype < GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD - || GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL < ptype) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Invalid message part of type %u and size %u.\n", - ptype, psize); - return GNUNET_SYSERR; - } - /** @todo FIXME: check message part order */ - } - return parts; -} - - -struct ParseMessageClosure -{ - struct GNUNET_PSYC_Environment *env; - const char **method_name; - const void **data; - uint16_t *data_size; - enum GNUNET_PSYC_MessageState msg_state; -}; - - -static void -parse_message_part_cb (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg) -{ - struct ParseMessageClosure *pmc = cls; - if (NULL == pmsg) - { - pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_ERROR; - return; - } - - switch (ntohs (pmsg->type)) - { - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD: - { - struct GNUNET_PSYC_MessageMethod * - pmeth = (struct GNUNET_PSYC_MessageMethod *) pmsg; - *pmc->method_name = (const char *) &pmeth[1]; - pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_METHOD; - break; - } - - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: - { - struct GNUNET_PSYC_MessageModifier * - pmod = (struct GNUNET_PSYC_MessageModifier *) pmsg; - - const char *name = (const char *) &pmod[1]; - const void *value = name + ntohs (pmod->name_size); - GNUNET_PSYC_env_add (pmc->env, pmod->oper, name, value, - ntohl (pmod->value_size)); - pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_MODIFIER; - break; - } - - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA: - *pmc->data = &pmsg[1]; - *pmc->data_size = ntohs (pmsg->size) - sizeof (*pmsg); - pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_DATA; - break; - - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: - pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_END; - break; - - default: - pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_ERROR; - } -} - - -/** - * Parse PSYC message. - * - * @param msg - * The PSYC message to parse. - * @param[out] method_name - * Pointer to the method name inside @a pmsg. - * @param env - * The environment for the message with a list of modifiers. - * @param[out] data - * Pointer to data inside @a msg. - * @param[out] data_size - * Size of @data is written here. - * - * @return #GNUNET_OK on success, - * #GNUNET_SYSERR on parse error. - */ -int -GNUNET_PSYC_message_parse (const struct GNUNET_PSYC_MessageHeader *msg, - const char **method_name, - struct GNUNET_PSYC_Environment *env, - const void **data, - uint16_t *data_size) -{ - struct ParseMessageClosure cls; - cls.env = env; - cls.method_name = method_name; - cls.data = data; - cls.data_size = data_size; - - struct GNUNET_PSYC_ReceiveHandle * - recv = GNUNET_PSYC_receive_create (NULL, parse_message_part_cb, &cls); - int ret = GNUNET_PSYC_receive_message (recv, msg); - GNUNET_PSYC_receive_destroy (recv); - - if (GNUNET_OK != ret) - return GNUNET_SYSERR; - - return (GNUNET_PSYC_MESSAGE_STATE_END == cls.msg_state) - ? GNUNET_OK - : GNUNET_NO; -} - - -/** - * Initialize PSYC message header. - */ -void -GNUNET_PSYC_message_header_init (struct GNUNET_PSYC_MessageHeader *pmsg, - const struct GNUNET_MULTICAST_MessageHeader *mmsg, - uint32_t flags) -{ - uint16_t size = ntohs (mmsg->header.size); - uint16_t psize = sizeof (*pmsg) + size - sizeof (*mmsg); - - pmsg->header.size = htons (psize); - pmsg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); - pmsg->message_id = mmsg->message_id; - pmsg->fragment_offset = mmsg->fragment_offset; - pmsg->flags = htonl (flags); - - GNUNET_memcpy (&pmsg[1], &mmsg[1], size - sizeof (*mmsg)); -} - - -/** - * Create a new PSYC message header from a multicast message. - */ -struct GNUNET_PSYC_MessageHeader * -GNUNET_PSYC_message_header_create (const struct GNUNET_MULTICAST_MessageHeader *mmsg, - uint32_t flags) -{ - struct GNUNET_PSYC_MessageHeader *pmsg; - uint16_t size = ntohs (mmsg->header.size); - uint16_t psize = sizeof (*pmsg) + size - sizeof (*mmsg); - - pmsg = GNUNET_malloc (psize); - GNUNET_PSYC_message_header_init (pmsg, mmsg, flags); - return pmsg; -} - - -/** - * Create a new PSYC message header from a PSYC message. - */ -struct GNUNET_PSYC_MessageHeader * -GNUNET_PSYC_message_header_create_from_psyc (const struct GNUNET_PSYC_Message *msg) -{ - uint16_t msg_size = ntohs (msg->header.size); - struct GNUNET_PSYC_MessageHeader * - pmsg = GNUNET_malloc (sizeof (*pmsg) + msg_size - sizeof (*msg)); - pmsg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); - pmsg->header.size = htons (sizeof (*pmsg) + msg_size - sizeof (*msg)); - GNUNET_memcpy (&pmsg[1], &msg[1], msg_size - sizeof (*msg)); - return pmsg; -} diff --git a/src/psycutil/psyc_slicer.c b/src/psycutil/psyc_slicer.c deleted file mode 100644 index 9b25d8a4b..000000000 --- a/src/psycutil/psyc_slicer.c +++ /dev/null @@ -1,711 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @author Gabor X Toth - * - * @file - * PSYC Slicer API - */ - -#include - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_psyc_util_lib.h" - -#define LOG(kind,...) GNUNET_log_from (kind, "psyc-util-slicer",__VA_ARGS__) - - -/** - * Handle for a try-and-slice instance. - */ -struct GNUNET_PSYC_Slicer -{ - /** - * Method handlers: H(method_name) -> SlicerMethodCallbacks - */ - struct GNUNET_CONTAINER_MultiHashMap *method_handlers; - - /** - * Modifier handlers: H(modifier_name) -> SlicerModifierCallbacks - */ - struct GNUNET_CONTAINER_MultiHashMap *modifier_handlers; - - /** - * Receive handle for incoming messages. - */ - struct GNUNET_PSYC_ReceiveHandle *recv; - - /** - * Currently being processed message. - */ - const struct GNUNET_PSYC_MessageHeader *msg; - - /** - * Currently being processed message part. - */ - const struct GNUNET_MessageHeader *pmsg; - - /** - * ID of currently being received message. - */ - uint64_t message_id; - - /** - * Fragment offset of currently being received message. - */ - uint64_t fragment_offset; - - /** - * Flags of currently being received message. - */ - uint32_t flags; - - /** - * Method name of currently being received message. - */ - char *method_name; - - /** - * Name of currently processed modifier. - */ - char *mod_name; - - /** - * Value of currently processed modifier. - */ - char *mod_value; - - /** - * Public key of the nym the current message originates from. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey nym_pub_key; - - /** - * Size of @a method_name (including terminating \0). - */ - uint16_t method_name_size; - - /** - * Size of @a modifier_name (including terminating \0). - */ - uint16_t mod_name_size; - - /** - * Size of modifier value fragment. - */ - uint16_t mod_value_size; - - /** - * Full size of modifier value. - */ - uint16_t mod_full_value_size; - - /** - * Remaining bytes from the value of the current modifier. - */ - uint16_t mod_value_remaining; - - /** - * Operator of currently processed modifier. - */ - uint8_t mod_oper; -}; - - -/** - * Callbacks for a slicer method handler. - */ -struct SlicerMethodCallbacks -{ - GNUNET_PSYC_MessageCallback msg_cb; - GNUNET_PSYC_MethodCallback method_cb; - GNUNET_PSYC_ModifierCallback modifier_cb; - GNUNET_PSYC_DataCallback data_cb; - GNUNET_PSYC_EndOfMessageCallback eom_cb; - void *cls; -}; - - -struct SlicerMethodRemoveClosure -{ - struct GNUNET_PSYC_Slicer *slicer; - struct SlicerMethodCallbacks rm_cbs; -}; - - -/** - * Callbacks for a slicer method handler. - */ -struct SlicerModifierCallbacks -{ - GNUNET_PSYC_ModifierCallback modifier_cb; - void *cls; -}; - - -struct SlicerModifierRemoveClosure -{ - struct GNUNET_PSYC_Slicer *slicer; - struct SlicerModifierCallbacks rm_cbs; -}; - - -/** - * Call a method handler for an incoming message part. - */ -static int -slicer_method_handler_notify (void *cls, const struct GNUNET_HashCode *key, - void *value) -{ - struct GNUNET_PSYC_Slicer *slicer = cls; - const struct GNUNET_MessageHeader *pmsg = slicer->pmsg; - struct SlicerMethodCallbacks *cbs = value; - - uint16_t ptype = ntohs (pmsg->type); - switch (ptype) - { - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD: - { - if (NULL != cbs->msg_cb) - cbs->msg_cb (cbs->cls, slicer->msg); - if (NULL == cbs->method_cb) - break; - struct GNUNET_PSYC_MessageMethod * - meth = (struct GNUNET_PSYC_MessageMethod *) pmsg; - cbs->method_cb (cbs->cls, slicer->msg, meth, slicer->message_id, - slicer->method_name); - break; - } - - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: - { - if (NULL == cbs->modifier_cb) - break; - struct GNUNET_PSYC_MessageModifier * - mod = (struct GNUNET_PSYC_MessageModifier *) pmsg; - cbs->modifier_cb (cbs->cls, slicer->msg, &mod->header, slicer->message_id, - mod->oper, (const char *) &mod[1], - (const void *) &mod[1] + ntohs (mod->name_size), - ntohs (mod->header.size) - sizeof (*mod) - ntohs (mod->name_size), - ntohs (mod->value_size)); - break; - } - - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: - { - if (NULL == cbs->modifier_cb) - break; - cbs->modifier_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id, - slicer->mod_oper, slicer->mod_name, &pmsg[1], - ntohs (pmsg->size) - sizeof (*pmsg), - slicer->mod_full_value_size); - break; - } - - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA: - { - if (NULL == cbs->data_cb) - break; - cbs->data_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id, - &pmsg[1], ntohs (pmsg->size) - sizeof (*pmsg)); - break; - } - - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: - if (NULL == cbs->eom_cb) - break; - cbs->eom_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id, GNUNET_NO); - break; - - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL: - if (NULL == cbs->eom_cb) - break; - cbs->eom_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id, GNUNET_YES); - break; - } - return GNUNET_YES; -} - - -/** - * Call a method handler for an incoming message part. - */ -static int -slicer_modifier_handler_notify (void *cls, const struct GNUNET_HashCode *key, - void *value) -{ - struct GNUNET_PSYC_Slicer *slicer = cls; - struct SlicerModifierCallbacks *cbs = value; - - cbs->modifier_cb (cbs->cls, slicer->msg, slicer->pmsg, slicer->message_id, - slicer->mod_oper, slicer->mod_name, slicer->mod_value, - slicer->mod_value_size, slicer->mod_full_value_size); - return GNUNET_YES; -} - - -/** - * Process an incoming message and call matching handlers. - * - * @param slicer - * The slicer to use. - * @param msg - * The message as it arrived from the network. - */ -void -GNUNET_PSYC_slicer_message (struct GNUNET_PSYC_Slicer *slicer, - const struct GNUNET_PSYC_MessageHeader *msg) -{ - GNUNET_PSYC_receive_message (slicer->recv, msg); -} - - -/** - * Process an incoming message part and call matching handlers. - * - * @param cls - * Closure. - * @param message_id - * ID of the message. - * @param flags - * Flags for the message. - * @see enum GNUNET_PSYC_MessageFlags - * @param msg - * The message part. as it arrived from the network. - */ -void -GNUNET_PSYC_slicer_message_part (struct GNUNET_PSYC_Slicer *slicer, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg) -{ - slicer->msg = msg; - slicer->pmsg = pmsg; - - uint64_t message_id = GNUNET_ntohll (msg->message_id); - - uint16_t ptype = ntohs (pmsg->type); - if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == ptype) - { - struct GNUNET_PSYC_MessageMethod * - meth = (struct GNUNET_PSYC_MessageMethod *) pmsg; - slicer->method_name_size = ntohs (meth->header.size) - sizeof (*meth); - slicer->method_name = GNUNET_malloc (slicer->method_name_size); - GNUNET_memcpy (slicer->method_name, &meth[1], slicer->method_name_size); - slicer->message_id = message_id; - } - else - { - GNUNET_assert (message_id == slicer->message_id); - } - - char *nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&msg->slave_pub_key); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Slicer received message of type %u and size %u, " - "with ID %" PRIu64 " and method %s from %s\n", - ptype, ntohs (pmsg->size), message_id, slicer->method_name, nym_str); - GNUNET_free (nym_str); - - /* try-and-slice modifier */ - - switch (ptype) - { - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: - { - struct GNUNET_PSYC_MessageModifier * - mod = (struct GNUNET_PSYC_MessageModifier *) pmsg; - slicer->mod_oper = mod->oper; - slicer->mod_name_size = ntohs (mod->name_size); - slicer->mod_name = GNUNET_malloc (slicer->mod_name_size); - GNUNET_memcpy (slicer->mod_name, &mod[1], slicer->mod_name_size); - slicer->mod_value = (char *) &mod[1] + slicer->mod_name_size; - slicer->mod_full_value_size = ntohs (mod->value_size); - slicer->mod_value_remaining = slicer->mod_full_value_size; - slicer->mod_value_size - = ntohs (mod->header.size) - sizeof (*mod) - slicer->mod_name_size; - // fall through - } - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: - if (ptype == GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT) - { - slicer->mod_value = (char *) &pmsg[1]; - slicer->mod_value_size = ntohs (pmsg->size) - sizeof (*pmsg); - } - slicer->mod_value_remaining -= slicer->mod_value_size; - char *name = GNUNET_malloc (slicer->mod_name_size); - GNUNET_memcpy (name, slicer->mod_name, slicer->mod_name_size); - do - { - struct GNUNET_HashCode key; - uint16_t name_len = strlen (name); - GNUNET_CRYPTO_hash (name, name_len, &key); - GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key, - slicer_modifier_handler_notify, - slicer); - char *p = strrchr (name, '_'); - if (NULL == p) - break; - *p = '\0'; - } while (1); - GNUNET_free (name); - } - - /* try-and-slice method */ - - char *name = GNUNET_malloc (slicer->method_name_size); - GNUNET_memcpy (name, slicer->method_name, slicer->method_name_size); - do - { - struct GNUNET_HashCode key; - uint16_t name_len = strlen (name); - GNUNET_CRYPTO_hash (name, name_len, &key); - GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key, - slicer_method_handler_notify, - slicer); - char *p = strrchr (name, '_'); - if (NULL == p) - break; - *p = '\0'; - } while (1); - GNUNET_free (name); - - if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype) - GNUNET_free (slicer->method_name); - - if (0 == slicer->mod_value_remaining && NULL != slicer->mod_name) - { - GNUNET_free (slicer->mod_name); - slicer->mod_name = NULL; - slicer->mod_name_size = 0; - slicer->mod_value_size = 0; - slicer->mod_full_value_size = 0; - slicer->mod_oper = 0; - } - - slicer->msg = NULL; - slicer->pmsg = NULL; -} - - -/** - * Create a try-and-slice instance. - * - * A slicer processes incoming messages and notifies callbacks about matching - * methods or modifiers encountered. - * - * @return A new try-and-slice construct. - */ -struct GNUNET_PSYC_Slicer * -GNUNET_PSYC_slicer_create (void) -{ - struct GNUNET_PSYC_Slicer *slicer = GNUNET_malloc (sizeof (*slicer)); - slicer->method_handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - slicer->modifier_handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - slicer->recv = GNUNET_PSYC_receive_create (NULL, - (GNUNET_PSYC_MessagePartCallback) - GNUNET_PSYC_slicer_message_part, - slicer); - return slicer; -} - - -/** - * Add a method to the try-and-slice instance. - * - * The callbacks are called for messages with a matching @a method_name prefix. - * - * @param slicer - * The try-and-slice instance to extend. - * @param method_name - * Name of the given method, use empty string to match all. - * @param method_cb - * Method handler invoked upon a matching message. - * @param modifier_cb - * Modifier handler, invoked after @a method_cb - * for each modifier in the message. - * @param data_cb - * Data handler, invoked after @a modifier_cb for each data fragment. - * @param eom_cb - * Invoked upon reaching the end of a matching message. - * @param cls - * Closure for the callbacks. - */ -void -GNUNET_PSYC_slicer_method_add (struct GNUNET_PSYC_Slicer *slicer, - const char *method_name, - GNUNET_PSYC_MessageCallback msg_cb, - GNUNET_PSYC_MethodCallback method_cb, - GNUNET_PSYC_ModifierCallback modifier_cb, - GNUNET_PSYC_DataCallback data_cb, - GNUNET_PSYC_EndOfMessageCallback eom_cb, - void *cls) -{ - struct GNUNET_HashCode key; - GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key); - - struct SlicerMethodCallbacks *cbs = GNUNET_malloc (sizeof (*cbs)); - cbs->msg_cb = msg_cb, - cbs->method_cb = method_cb; - cbs->modifier_cb = modifier_cb; - cbs->data_cb = data_cb; - cbs->eom_cb = eom_cb; - cbs->cls = cls; - - GNUNET_CONTAINER_multihashmap_put (slicer->method_handlers, &key, cbs, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); -} - - -static int -slicer_method_remove (void *cls, const struct GNUNET_HashCode *key, void *value) -{ - struct SlicerMethodRemoveClosure *rm_cls = cls; - struct GNUNET_PSYC_Slicer *slicer = rm_cls->slicer; - struct SlicerMethodCallbacks *rm_cbs = &rm_cls->rm_cbs; - struct SlicerMethodCallbacks *cbs = value; - - if ((NULL == rm_cbs->msg_cb || cbs->msg_cb == rm_cbs->msg_cb) - && (NULL == rm_cbs->method_cb || cbs->method_cb == rm_cbs->method_cb) - && (NULL == rm_cbs->modifier_cb || cbs->modifier_cb == rm_cbs->modifier_cb) - && (NULL == rm_cbs->data_cb || cbs->data_cb == rm_cbs->data_cb) - && (NULL == rm_cbs->eom_cb || cbs->eom_cb == rm_cbs->eom_cb)) - { - GNUNET_CONTAINER_multihashmap_remove (slicer->method_handlers, key, cbs); - GNUNET_free (cbs); - return GNUNET_NO; - } - return GNUNET_YES; -} - - -/** - * Remove a registered method from the try-and-slice instance. - * - * Removes one matching handler registered with the given - * @a method_name and callbacks. - * - * @param slicer - * The try-and-slice instance. - * @param method_name - * Name of the method to remove. - * @param method_cb - * Method handler. - * @param modifier_cb - * Modifier handler. - * @param data_cb - * Data handler. - * @param eom_cb - * End of message handler. - * - * @return #GNUNET_OK if a method handler was removed, - * #GNUNET_NO if no handler matched the given method name and callbacks. - */ -int -GNUNET_PSYC_slicer_method_remove (struct GNUNET_PSYC_Slicer *slicer, - const char *method_name, - GNUNET_PSYC_MessageCallback msg_cb, - GNUNET_PSYC_MethodCallback method_cb, - GNUNET_PSYC_ModifierCallback modifier_cb, - GNUNET_PSYC_DataCallback data_cb, - GNUNET_PSYC_EndOfMessageCallback eom_cb) -{ - struct GNUNET_HashCode key; - GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key); - - struct SlicerMethodRemoveClosure rm_cls; - rm_cls.slicer = slicer; - struct SlicerMethodCallbacks *rm_cbs = &rm_cls.rm_cbs; - rm_cbs->msg_cb = msg_cb; - rm_cbs->method_cb = method_cb; - rm_cbs->modifier_cb = modifier_cb; - rm_cbs->data_cb = data_cb; - rm_cbs->eom_cb = eom_cb; - - return - (GNUNET_SYSERR - == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key, - slicer_method_remove, - &rm_cls)) - ? GNUNET_NO - : GNUNET_OK; -} - - -/** - * Watch a place for changed objects. - * - * @param slicer - * The try-and-slice instance. - * @param object_filter - * Object prefix to match. - * @param modifier_cb - * Function to call when encountering a state modifier. - * @param cls - * Closure for callback. - */ -void -GNUNET_PSYC_slicer_modifier_add (struct GNUNET_PSYC_Slicer *slicer, - const char *object_filter, - GNUNET_PSYC_ModifierCallback modifier_cb, - void *cls) -{ - struct SlicerModifierCallbacks *cbs = GNUNET_malloc (sizeof *cbs); - cbs->modifier_cb = modifier_cb; - cbs->cls = cls; - - struct GNUNET_HashCode key; - GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key); - GNUNET_CONTAINER_multihashmap_put (slicer->modifier_handlers, &key, cbs, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); -} - - -static int -slicer_modifier_remove (void *cls, const struct GNUNET_HashCode *key, void *value) -{ - struct SlicerModifierRemoveClosure *rm_cls = cls; - struct GNUNET_PSYC_Slicer *slicer = rm_cls->slicer; - struct SlicerModifierCallbacks *rm_cbs = &rm_cls->rm_cbs; - struct SlicerModifierCallbacks *cbs = value; - - if (cbs->modifier_cb == rm_cbs->modifier_cb) - { - GNUNET_CONTAINER_multihashmap_remove (slicer->modifier_handlers, key, cbs); - GNUNET_free (cbs); - return GNUNET_NO; - } - return GNUNET_YES; -} - - -/** - * Remove a registered modifier from the try-and-slice instance. - * - * Removes one matching handler registered with the given - * @a object_filter and @a modifier_cb. - * - * @param slicer - * The try-and-slice instance. - * @param object_filter - * Object prefix to match. - * @param modifier_cb - * Function to call when encountering a state modifier changes. - */ -int -GNUNET_PSYC_slicer_modifier_remove (struct GNUNET_PSYC_Slicer *slicer, - const char *object_filter, - GNUNET_PSYC_ModifierCallback modifier_cb) -{ - struct GNUNET_HashCode key; - GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key); - - struct SlicerModifierRemoveClosure rm_cls; - rm_cls.slicer = slicer; - struct SlicerModifierCallbacks *rm_cbs = &rm_cls.rm_cbs; - rm_cbs->modifier_cb = modifier_cb; - - return - (GNUNET_SYSERR - == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key, - slicer_modifier_remove, - &rm_cls)) - ? GNUNET_NO - : GNUNET_OK; - } - - -static int -slicer_method_free (void *cls, const struct GNUNET_HashCode *key, void *value) -{ - struct SlicerMethodCallbacks *cbs = value; - GNUNET_free (cbs); - return GNUNET_YES; -} - - -static int -slicer_modifier_free (void *cls, const struct GNUNET_HashCode *key, void *value) -{ - struct SlicerModifierCallbacks *cbs = value; - GNUNET_free (cbs); - return GNUNET_YES; -} - - -/** - * Remove all registered method handlers. - * - * @param slicer - * Slicer to clear. - */ -void -GNUNET_PSYC_slicer_method_clear (struct GNUNET_PSYC_Slicer *slicer) -{ - GNUNET_CONTAINER_multihashmap_iterate (slicer->method_handlers, - slicer_method_free, NULL); - GNUNET_CONTAINER_multihashmap_clear (slicer->method_handlers); -} - - -/** - * Remove all registered modifier handlers. - * - * @param slicer - * Slicer to clear. - */ -void -GNUNET_PSYC_slicer_modifier_clear (struct GNUNET_PSYC_Slicer *slicer) -{ - GNUNET_CONTAINER_multihashmap_iterate (slicer->modifier_handlers, - slicer_modifier_free, NULL); - GNUNET_CONTAINER_multihashmap_clear (slicer->modifier_handlers); -} - - -/** - * Remove all registered method & modifier handlers. - * - * @param slicer - * Slicer to clear. - */ -void -GNUNET_PSYC_slicer_clear (struct GNUNET_PSYC_Slicer *slicer) -{ - GNUNET_PSYC_slicer_method_clear (slicer); - GNUNET_PSYC_slicer_modifier_clear (slicer); -} - - -/** - * Destroy a given try-and-slice instance. - * - * @param slicer - * Slicer to destroy - */ -void -GNUNET_PSYC_slicer_destroy (struct GNUNET_PSYC_Slicer *slicer) -{ - GNUNET_PSYC_slicer_clear (slicer); - GNUNET_CONTAINER_multihashmap_destroy (slicer->method_handlers); - GNUNET_CONTAINER_multihashmap_destroy (slicer->modifier_handlers); - GNUNET_PSYC_receive_destroy (slicer->recv); - GNUNET_free (slicer); -} diff --git a/src/psycutil/test_psyc_env.c b/src/psycutil/test_psyc_env.c deleted file mode 100644 index 432e15503..000000000 --- a/src/psycutil/test_psyc_env.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * This file is part of GNUnet. - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @author Gabor X Toth - * - * @file - * Tests for the environment library. - */ - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_testing_lib.h" -#include "gnunet_psyc_util_lib.h" - -struct GNUNET_PSYC_Modifier mods[] = { - { .oper = GNUNET_PSYC_OP_SET, - .name = "_foo", .value = "foo", .value_size = 3 }, - - { .oper = GNUNET_PSYC_OP_ASSIGN, - .name = "_foo_bar", .value = "foo bar", .value_size = 7 }, - - { .oper = GNUNET_PSYC_OP_AUGMENT, - .name = "_foo_bar_baz", .value = "foo bar baz", .value_size = 11 } -}; - -struct ItCls -{ - size_t n; -}; - -int -iterator (void *cls, enum GNUNET_PSYC_Operator oper, - const char *name, const char *value, uint32_t value_size) -{ - struct ItCls *it_cls = cls; - struct GNUNET_PSYC_Modifier *m = &mods[it_cls->n++]; - - GNUNET_assert (oper == m->oper); - GNUNET_assert (value_size == m->value_size); - GNUNET_assert (0 == memcmp (name, m->name, strlen (m->name))); - GNUNET_assert (0 == memcmp (value, m->value, m->value_size)); - - return GNUNET_YES; -} - -int -main (int argc, char *argv[]) -{ - GNUNET_log_setup ("test-env", "WARNING", NULL); - - struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); - GNUNET_assert (NULL != env); - int i, len = 3; - - for (i = 0; i < len; i++) - { - GNUNET_PSYC_env_add (env, mods[i].oper, mods[i].name, - mods[i].value, mods[i].value_size); - } - - struct ItCls it_cls = { .n = 0 }; - GNUNET_PSYC_env_iterate (env, iterator, &it_cls); - GNUNET_assert (len == it_cls.n); - - for (i = 0; i < len; i++) - { - enum GNUNET_PSYC_Operator oper; - const char *name; - const void *value; - size_t value_size; - GNUNET_PSYC_env_shift (env, &oper, &name, &value, &value_size); - GNUNET_assert (len - i - 1 == GNUNET_PSYC_env_get_count (env)); - } - - GNUNET_PSYC_env_destroy (env); - - return 0; -} diff --git a/src/social/.gitignore b/src/social/.gitignore deleted file mode 100644 index 875aa1105..000000000 --- a/src/social/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -gnunet-social -gnunet-service-social -test_social diff --git a/src/social/Makefile.am b/src/social/Makefile.am deleted file mode 100644 index 94a9ba108..000000000 --- a/src/social/Makefile.am +++ /dev/null @@ -1,79 +0,0 @@ -# This Makefile.am is in the public domain -AM_CPPFLAGS = -I$(top_srcdir)/src/include - -pkgcfgdir= $(pkgdatadir)/config.d/ - -libexecdir= $(pkglibdir)/libexec/ - -pkgcfg_DATA = \ - social.conf - - -if MINGW - WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -endif - -if USE_COVERAGE - AM_CFLAGS = --coverage -O0 - XLIB = -lgcov -endif - -lib_LTLIBRARIES = libgnunetsocial.la - -libgnunetsocial_la_SOURCES = \ - social_api.c social.h -libgnunetsocial_la_LIBADD = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/psycutil/libgnunetpsycutil.la \ - $(GN_LIBINTL) $(XLIB) -libgnunetsocial_la_LDFLAGS = \ - $(GN_LIB_LDFLAGS) $(WINFLAGS) \ - -version-info 0:0:0 - -bin_PROGRAMS = \ - gnunet-social - -libexec_PROGRAMS = \ - gnunet-service-social - -gnunet_social_SOURCES = \ - gnunet-social.c -gnunet_social_LDADD = \ - libgnunetsocial.la \ - $(top_builddir)/src/psycutil/libgnunetpsycutil.la \ - $(top_builddir)/src/util/libgnunetutil.la - -gnunet_service_social_SOURCES = \ - gnunet-service-social.c -gnunet_service_social_LDADD = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(top_builddir)/src/psycutil/libgnunetpsycutil.la \ - $(top_builddir)/src/psyc/libgnunetpsyc.la \ - $(top_builddir)/src/identity/libgnunetidentity.la \ - $(top_builddir)/src/gns/libgnunetgns.la \ - $(top_builddir)/src/namestore/libgnunetnamestore.la \ - $(GN_LIBINTL) - - -if HAVE_TESTING -check_PROGRAMS = \ - test_social -endif - -if ENABLE_TEST_RUN -AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; -TESTS = $(check_PROGRAMS) -endif - -test_social_SOURCES = \ - test_social.c -test_social_LDADD = \ - libgnunetsocial.la \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/psycutil/libgnunetpsycutil.la \ - $(top_builddir)/src/identity/libgnunetidentity.la - -EXTRA_DIST = \ - test_social.conf diff --git a/src/social/gnunet-service-social.c b/src/social/gnunet-service-social.c deleted file mode 100644 index 33fabae5d..000000000 --- a/src/social/gnunet-service-social.c +++ /dev/null @@ -1,3760 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file social/gnunet-service-social.c - * @brief Social service - * @author Gabor X Toth - */ - -#include -#include - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_constants.h" -#include "gnunet_protocols.h" -#include "gnunet_identity_service.h" -#include "gnunet_namestore_service.h" -#include "gnunet_gns_service.h" -#include "gnunet_statistics_service.h" -#include "gnunet_psyc_service.h" -#include "gnunet_psyc_util_lib.h" -#include "gnunet_social_service.h" -#include "social.h" - - -/** - * Handle to our current configuration. - */ -static const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * Service handle. - */ -static struct GNUNET_SERVICE_Handle *service; - -/* Handles to other services */ -static struct GNUNET_IDENTITY_Handle *id; -static struct GNUNET_GNS_Handle *gns; -static struct GNUNET_NAMESTORE_Handle *namestore; -static struct GNUNET_STATISTICS_Handle *stats; - -/** - * ID of this peer. - */ -static struct GNUNET_PeerIdentity this_peer; - -/** - * All connected hosts. - * H(place_pub_key) -> struct Host - */ -static struct GNUNET_CONTAINER_MultiHashMap *hosts; - -/** - * All connected guests. - * H(place_pub_key) -> struct Guest - */ -static struct GNUNET_CONTAINER_MultiHashMap *guests; - -/** - * Connected guests per place. - * H(place_pub_key) -> ego_pub_key -> struct Guest - */ -static struct GNUNET_CONTAINER_MultiHashMap *place_guests; - -/** - * Places entered as host or guest. - * H(place_pub_key) -> struct HostEnterRequest OR struct GuestEnterRequest - */ -static struct GNUNET_CONTAINER_MultiHashMap *places; - -/** - * Places entered per application. - * H(app_id) -> H(place_pub_key) -> NULL - */ -static struct GNUNET_CONTAINER_MultiHashMap *apps_places; - -/** - * Application subscriptions per place. - * H(place_pub_key) -> H(app_id) - */ -//static struct GNUNET_CONTAINER_MultiHashMap *places_apps; - -/** - * Connected applications. - * H(app_id) -> struct Application - */ -static struct GNUNET_CONTAINER_MultiHashMap *apps; - -/** - * All egos. - * H(ego_pub_key) -> struct Ego - */ -static struct GNUNET_CONTAINER_MultiHashMap *egos; - -/** - * Directory for storing social data. - * Default: $GNUNET_DATA_HOME/social - */ -static char *dir_social; - -/** - * Directory for storing place data. - * $dir_social/places - */ -static char *dir_places; - -/** - * Directory for storing app data. - * $dir_social/apps - */ -static char *dir_apps; - - -/** - * Message fragment transmission queue. - */ -struct FragmentTransmitQueue -{ - struct FragmentTransmitQueue *prev; - struct FragmentTransmitQueue *next; - - struct GNUNET_SERVICE_Client *client; - - /** - * Pointer to the next message part inside the data after this struct. - */ - struct GNUNET_MessageHeader *next_part; - - /** - * Size of message. - */ - uint16_t size; - - /** - * @see enum GNUNET_PSYC_MessageState - */ - uint8_t state; - - /* Followed by one or more message parts. */ -}; - - -/** - * Message transmission queue. - */ -struct MessageTransmitQueue -{ - struct MessageTransmitQueue *prev; - struct MessageTransmitQueue *next; - - struct FragmentTransmitQueue *frags_head; - struct FragmentTransmitQueue *frags_tail; - - struct GNUNET_SERVICE_Client *client; -}; - -/** - * List of connected clients. - */ -struct ClientListItem -{ - struct ClientListItem *prev; - struct ClientListItem *next; - - struct GNUNET_SERVICE_Client *client; -}; - - -/** - * Common part of the client context for both a host and guest. - */ -struct Place -{ - struct ClientListItem *clients_head; - struct ClientListItem *clients_tail; - - struct MessageTransmitQueue *tmit_msgs_head; - struct MessageTransmitQueue *tmit_msgs_tail; - - struct GNUNET_PSYC_Channel *channel; - - /** - * Private key of home in case of a host. - */ - struct GNUNET_CRYPTO_EddsaPublicKey key; - - /** - * Public key of place. - */ - struct GNUNET_CRYPTO_EddsaPublicKey pub_key; - - /** - * Hash of @a pub_key. - */ - struct GNUNET_HashCode pub_key_hash; - - /** - * Private key of ego. - */ - struct GNUNET_CRYPTO_EcdsaPrivateKey ego_key; - - /** - * Public key of ego. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; - - /** - * Hash of @a ego_pub_key. - */ - struct GNUNET_HashCode ego_pub_hash; - - /** - * Slicer for processing incoming messages. - */ - struct GNUNET_PSYC_Slicer *slicer; - - /** - * Last message ID received for the place. - * 0 if there is no such message. - */ - uint64_t max_message_id; - - /** - * Offset where the file is currently being written. - */ - uint64_t file_offset; - - /** - * Whether or not to save the file (#GNUNET_YES or #GNUNET_NO) - */ - uint8_t file_save; - - /** - * Is this place ready to receive messages from client? - * #GNUNET_YES or #GNUNET_NO - */ - uint8_t is_ready; - - /** - * Is the client disconnecting? - * #GNUNET_YES or #GNUNET_NO - */ - uint8_t is_disconnecting; - - /** - * Is this a host (#GNUNET_YES), or guest (#GNUNET_NO)? - */ - uint8_t is_host; - - union { - struct Host *host; - struct Guest *guest; - }; -}; - - -/** - * Client context for a host. - */ -struct Host -{ - /** - * Place struct common for Host and Guest - */ - struct Place place; - - /** - * Handle for the multicast origin. - */ - struct GNUNET_PSYC_Master *master; - - /** - * Transmit handle for multicast. - */ - struct GNUNET_PSYC_MasterTransmitHandle *tmit_handle; - - /** - * Incoming join requests. - * guest_key -> struct GNUNET_PSYC_JoinHandle * - */ - struct GNUNET_CONTAINER_MultiHashMap *join_reqs; - - /** - * Messages being relayed. - */ - struct GNUNET_CONTAINER_MultiHashMap *relay_msgs; - - /** - * @see enum GNUNET_PSYC_Policy - */ - enum GNUNET_PSYC_Policy policy; -}; - - -/** - * Client context for a guest. - */ -struct Guest -{ - /** - * Place struct common for Host and Guest. - */ - struct Place place; - - /** - * Handle for the PSYC slave. - */ - struct GNUNET_PSYC_Slave *slave; - - /** - * Transmit handle for multicast. - */ - struct GNUNET_PSYC_SlaveTransmitHandle *tmit_handle; - - /** - * Peer identity of the origin. - */ - struct GNUNET_PeerIdentity origin; - - /** - * Number of items in @a relays. - */ - uint32_t relay_count; - - /** - * Relays that multicast can use to connect. - */ - struct GNUNET_PeerIdentity *relays; - - /** - * Join request to be transmitted to the master on join. - */ - struct GNUNET_MessageHeader *join_req; // FIXME: not used! - - /** - * Join decision received from PSYC. - */ - struct GNUNET_PSYC_JoinDecisionMessage *join_dcsn; - - /** - * Join flags for the PSYC service. - */ - enum GNUNET_PSYC_SlaveJoinFlags join_flags; -}; - - -/** - * Context for a client. - */ -struct Client -{ - /** - * Client handle. - */ - struct GNUNET_SERVICE_Client *client; - - /** - * Place where the client entered. - */ - struct Place *place; - - /** - * Message queue for the message currently being transmitted - * by this client. - */ - struct MessageTransmitQueue *tmit_msg; - - /** - * ID for application clients. - */ - char *app_id; -}; - - -struct Application -{ - struct ClientListItem *clients_head; - struct ClientListItem *clients_tail; -}; - - -struct Ego { - struct GNUNET_CRYPTO_EcdsaPrivateKey key; - char *name; -}; - - -struct OperationClosure -{ - struct Client *client; - uint64_t op_id; - uint32_t flags; -}; - - -static int -psyc_transmit_message (struct Place *plc); - - -/** - * Clean up place data structures after a client disconnected. - * - * @param cls the `struct Place` to clean up - */ -static void -cleanup_place (void *cls); - - -static struct MessageTransmitQueue * -psyc_transmit_queue_message (struct Place *plc, - struct GNUNET_SERVICE_Client *client, - size_t data_size, - const void *data, - uint16_t first_ptype, uint16_t last_ptype, - struct MessageTransmitQueue *tmit_msg); - - -static int -place_entry_cleanup (void *cls, - const struct GNUNET_HashCode *key, - void *value) -{ - struct Place *plc = value; - - cleanup_place (plc); - return GNUNET_YES; -} - - -/** - * Task run during shutdown. - * - * @param cls unused - */ -static void -shutdown_task (void *cls) -{ - GNUNET_CONTAINER_multihashmap_iterate (hosts, place_entry_cleanup, NULL); - GNUNET_CONTAINER_multihashmap_iterate (guests, place_entry_cleanup, NULL); - - if (NULL != id) - { - GNUNET_IDENTITY_disconnect (id); - id = NULL; - } - if (NULL != namestore) - { - GNUNET_NAMESTORE_disconnect (namestore); - namestore = NULL; - } - if (NULL != gns) - { - GNUNET_GNS_disconnect (gns); - gns = NULL; - } - if (NULL != stats) - { - GNUNET_STATISTICS_destroy (stats, GNUNET_YES); - stats = NULL; - } -} - - -/** - * Clean up host data structures after a client disconnected. - */ -static void -cleanup_host (struct Host *hst) -{ - struct Place *plc = &hst->place; - - GNUNET_CONTAINER_multihashmap_destroy (hst->join_reqs); - GNUNET_CONTAINER_multihashmap_destroy (hst->relay_msgs); - GNUNET_CONTAINER_multihashmap_remove (hosts, &plc->pub_key_hash, plc); -} - - -/** - * Clean up guest data structures after a client disconnected. - */ -static void -cleanup_guest (struct Guest *gst) -{ - struct Place *plc = &gst->place; - struct GNUNET_CONTAINER_MultiHashMap * - plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests, - &plc->pub_key_hash); - if (NULL != plc_gst) - { - GNUNET_CONTAINER_multihashmap_remove (plc_gst, &plc->ego_pub_hash, gst); - - if (0 == GNUNET_CONTAINER_multihashmap_size (plc_gst)) - { - GNUNET_CONTAINER_multihashmap_remove (place_guests, &plc->pub_key_hash, - plc_gst); - GNUNET_CONTAINER_multihashmap_destroy (plc_gst); - } - } - GNUNET_CONTAINER_multihashmap_remove (guests, &plc->pub_key_hash, gst); - if (NULL != gst->join_req) - GNUNET_free (gst->join_req); - if (NULL != gst->relays) - GNUNET_free (gst->relays); - GNUNET_CONTAINER_multihashmap_remove (guests, &plc->pub_key_hash, plc); -} - - -/** - * Clean up place data structures after a client disconnected. - * - * @param cls the `struct Place` to clean up - */ -static void -cleanup_place (void *cls) -{ - struct Place *plc = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "cleaning up place %s\n", - GNUNET_h2s (&plc->pub_key_hash)); - - (GNUNET_YES == plc->is_host) - ? cleanup_host ((struct Host *) plc) - : cleanup_guest ((struct Guest *) plc); - - GNUNET_PSYC_slicer_destroy (plc->slicer); - GNUNET_free (plc); -} - - -/** - * Called whenever a client is disconnected. - * Frees our resources associated with that client. - * - * @param cls closure - * @param client identification of the client - * @param app_ctx must match @a client - */ -static void -client_notify_disconnect (void *cls, - struct GNUNET_SERVICE_Client *client, - void *app_ctx) -{ - struct Client *c = app_ctx; - struct Place *plc = c->place; - - if (NULL != c->app_id) - GNUNET_free (c->app_id); - - GNUNET_free (c); - - if (NULL == plc) - return; // application client, nothing to do - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Client (%s) disconnected from place %s\n", - plc, (GNUNET_YES == plc->is_host) ? "host" : "guest", - GNUNET_h2s (&plc->pub_key_hash)); - - struct ClientListItem *cli = plc->clients_head; - while (NULL != cli) - { - if (cli->client == client) - { - GNUNET_CONTAINER_DLL_remove (plc->clients_head, - plc->clients_tail, - cli); - GNUNET_free (cli); - break; - } - cli = cli->next; - } - if (GNUNET_YES == plc->is_disconnecting) - { - GNUNET_PSYC_slicer_destroy (plc->slicer); - GNUNET_free (plc); - } -} - - -/** - * A new client connected. - * - * @param cls NULL - * @param client client to add - * @param mq message queue for @a client - * @return @a client - */ -static void * -client_notify_connect (void *cls, - struct GNUNET_SERVICE_Client *client, - struct GNUNET_MQ_Handle *mq) -{ - struct Client *c = GNUNET_new (struct Client); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Client %p connected with queue %p\n", - client, - mq); - c->client = client; - return c; -} - - -/** - * Send message to all clients connected to a place and - * takes care of freeing @env. - */ -static void -place_send_msg (const struct Place *plc, - struct GNUNET_MQ_Envelope *env) -{ - struct ClientListItem *cli = plc->clients_head; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Sending message to clients of place.\n", plc); - while (NULL != cli) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending message to client %p\n", - cli); - GNUNET_MQ_send_copy (GNUNET_SERVICE_client_get_mq (cli->client), - env); - cli = cli->next; - } - GNUNET_MQ_discard (env); -} - - -static void -place_send_leave_ack (struct Place *plc) -{ - struct GNUNET_MQ_Envelope *env; - - for (struct ClientListItem *cli = plc->clients_head; - NULL != cli; - cli = cli->next) - { - env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE_ACK); - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (cli->client), - env); - } -} - - -/** - * Send a result code back to the client. - * - * @param client - * Client that should receive the result code. - * @param result_code - * Code to transmit. - * @param op_id - * Operation ID in network byte order. - * @param data - * Data payload or NULL. - * @param data_size - * Size of @a data. - */ -static void -client_send_result (struct GNUNET_SERVICE_Client *client, uint64_t op_id, - int64_t result_code, const void *data, uint16_t data_size) -{ - struct GNUNET_MQ_Envelope *env; - struct GNUNET_OperationResultMessage *res; - - env = GNUNET_MQ_msg_extra (res, - data_size, - GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE); - res->result_code = GNUNET_htonll (result_code); - res->op_id = op_id; - if (0 < data_size) - GNUNET_memcpy (&res[1], data, data_size); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Sending result to client for operation #%" PRIu64 ": " - "%" PRId64 " (size: %u)\n", - client, GNUNET_ntohll (op_id), result_code, data_size); - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env); -} - - -static void -client_send_host_enter_ack (struct GNUNET_SERVICE_Client *client, - struct Host *hst, uint32_t result) -{ - struct GNUNET_MQ_Envelope *env; - struct HostEnterAck *hack; - struct Place *plc = &hst->place; - - env = GNUNET_MQ_msg (hack, - GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK); - hack->result_code = htonl (result); - hack->max_message_id = GNUNET_htonll (plc->max_message_id); - hack->place_pub_key = plc->pub_key; - - if (NULL != client) - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), - env); - else - place_send_msg (plc, env); -} - - -/** - * Called after a PSYC master is started. - */ -static void -psyc_master_started (void *cls, int result, uint64_t max_message_id) -{ - struct Host *hst = cls; - struct Place *plc = &hst->place; - plc->max_message_id = max_message_id; - plc->is_ready = GNUNET_YES; - - client_send_host_enter_ack (NULL, hst, result); -} - - -/** - * Called when a PSYC master receives a join request. - */ -static void -psyc_recv_join_request (void *cls, - const struct GNUNET_PSYC_JoinRequestMessage *req, - const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - const struct GNUNET_PSYC_Message *join_msg, - struct GNUNET_PSYC_JoinHandle *jh) -{ - struct Host *hst = cls; - struct GNUNET_HashCode slave_key_hash; - GNUNET_CRYPTO_hash (slave_key, sizeof (*slave_key), &slave_key_hash); - GNUNET_CONTAINER_multihashmap_put (hst->join_reqs, &slave_key_hash, jh, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - place_send_msg (&hst->place, - GNUNET_MQ_msg_copy (&req->header)); -} - - -/** - * Called after a PSYC slave is connected. - */ -static void -psyc_slave_connected (void *cls, int result, uint64_t max_message_id) -{ - struct GNUNET_PSYC_CountersResultMessage *res; - struct GNUNET_MQ_Envelope *env; - struct Guest *gst = cls; - struct Place *plc = &gst->place; - - plc->max_message_id = max_message_id; - plc->is_ready = GNUNET_YES; - env = GNUNET_MQ_msg (res, - GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK); - res->result_code = - (result != GNUNET_SYSERR) ? htonl (GNUNET_OK) : htonl (GNUNET_SYSERR); - res->max_message_id = GNUNET_htonll (plc->max_message_id); - place_send_msg (plc, env); -} - - -static void -slave_parted_after_join_decision (void *cls) -{ - struct Guest *gst = cls; - - GNUNET_assert (NULL != gst->join_dcsn); - place_send_msg (&gst->place, GNUNET_MQ_msg_copy (&gst->join_dcsn->header)); -} - - -/** - * Called when a PSYC slave receives a join decision. - */ -static void -psyc_recv_join_dcsn (void *cls, - const struct GNUNET_PSYC_JoinDecisionMessage *dcsn, - int is_admitted, - const struct GNUNET_PSYC_Message *join_msg) -{ - struct Guest *gst = cls; - - gst->join_dcsn = GNUNET_malloc (dcsn->header.size); - GNUNET_memcpy (gst->join_dcsn, - dcsn, - dcsn->header.size); - if (GNUNET_NO == is_admitted) - { - GNUNET_PSYC_slave_part (gst->slave, - GNUNET_NO, - &slave_parted_after_join_decision, - gst); - gst->slave = NULL; - return; - } - place_send_msg (&gst->place, GNUNET_MQ_msg_copy (&gst->join_dcsn->header)); -} - - -/** - * Called when a PSYC master or slave receives a message. - */ -static void -psyc_recv_message (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg) -{ - struct Place *plc = cls; - - char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&msg->slave_pub_key); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Received PSYC message of size %u from %s.\n", - plc, ntohs (msg->header.size), str); - GNUNET_free (str); - - GNUNET_PSYC_slicer_message (plc->slicer, msg); - - place_send_msg (plc, GNUNET_MQ_msg_copy (&msg->header)); -} - - -/** - * Relay a message part received from a guest to the the place. - * - * @param hst - * Host. - * @param pmsg - * Message part. - * @param nym_pub_key - * Nym the message is received from. - */ -static void -host_relay_message_part (struct Host *hst, - const struct GNUNET_MessageHeader *pmsg, - const struct GNUNET_CRYPTO_EcdsaPublicKey *nym_pub_key) -{ - /* separate queue per nym */ - struct GNUNET_HashCode nym_pub_hash; - GNUNET_CRYPTO_hash (nym_pub_key, sizeof (*nym_pub_key), &nym_pub_hash); - - struct MessageTransmitQueue * - tmit_msg = GNUNET_CONTAINER_multihashmap_get (hst->relay_msgs, &nym_pub_hash); - - uint16_t ptype = ntohs (pmsg->type); - - if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == ptype) - { - /* FIXME: last message was unfinished, cancel & remove from queue */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "FIXME: last message was unfinished.\n"); - } - - tmit_msg = psyc_transmit_queue_message (&hst->place, NULL, ntohs (pmsg->size), - pmsg, ptype, ptype, tmit_msg); - - switch (ptype) - { - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD: - GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_put - (hst->relay_msgs, &nym_pub_hash, tmit_msg, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); - break; - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL: - GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove - (hst->relay_msgs, &nym_pub_hash, tmit_msg)); - break; - } -} - - -/** - * Received a method to be relayed from a guest. - */ -static void -place_recv_relay_method (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_PSYC_MessageMethod *meth, - uint64_t message_id, - const char *method_name) -{ - struct Place *plc = cls; - - if (GNUNET_PSYC_MESSAGE_REQUEST & ntohs (msg->flags) - && GNUNET_YES == plc->is_host) - { - struct Host *hst = cls; - host_relay_message_part (hst, &meth->header, &msg->slave_pub_key); - } -} - - -/** - * Received a modifier to be relayed from a guest. - */ -static void -place_recv_relay_modifier (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg, - uint64_t message_id, - enum GNUNET_PSYC_Operator oper, - const char *name, - const void *value, - uint16_t value_size, - uint16_t full_value_size) -{ - struct Place *plc = cls; - - if (GNUNET_PSYC_MESSAGE_REQUEST & ntohs (msg->flags) - && GNUNET_YES == plc->is_host) - { - struct Host *hst = cls; - host_relay_message_part (hst, pmsg, &msg->slave_pub_key); - } -} - -/** - * Received a data fragment to be relayed from a guest. - */ -static void -place_recv_relay_data (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg, - uint64_t message_id, - const void *data, - uint16_t data_size) -{ - struct Place *plc = cls; - - if (GNUNET_PSYC_MESSAGE_REQUEST & ntohs (msg->flags) - && GNUNET_YES == plc->is_host) - { - struct Host *hst = cls; - host_relay_message_part (hst, pmsg, &msg->slave_pub_key); - } -} - - -/** - * Received end of message to be relayed from a guest. - */ -static void -place_recv_relay_eom (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg, - uint64_t message_id, - uint8_t is_cancelled) -{ - struct Place *plc = cls; - - if (GNUNET_PSYC_MESSAGE_REQUEST & ntohs (msg->flags) - && GNUNET_YES == plc->is_host) - { - struct Host *hst = cls; - host_relay_message_part (hst, pmsg, &msg->slave_pub_key); - } -} - - -/** - * Received a method to be saved to disk. - * - * Create a new file for writing the data part of the message into, - * if the file does not yet exist. - */ -static void -place_recv_save_method (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_PSYC_MessageMethod *meth, - uint64_t message_id, - const char *method_name) -{ - struct Place *plc = cls; - plc->file_offset = 0; - plc->file_save = GNUNET_NO; - - char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (&plc->pub_key); - char *filename = NULL; - GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%" PRIu64 ".part", - dir_social, DIR_SEPARATOR, - "files", DIR_SEPARATOR, - place_pub_str, DIR_SEPARATOR, - GNUNET_ntohll (msg->message_id)); - GNUNET_free (place_pub_str); - - /* save if does not already exist */ - if (GNUNET_YES != GNUNET_DISK_file_test (filename)) - { - if (0 == GNUNET_DISK_fn_write (filename, NULL, 0, - GNUNET_DISK_PERM_USER_READ - | GNUNET_DISK_PERM_USER_WRITE)) - { - plc->file_save = GNUNET_YES; - } - else - { - GNUNET_break (0); - } - } - GNUNET_free (filename); -} - - -/** - * Received a data fragment to be saved to disk. - * - * Append data fragment to the file. - */ -static void -place_recv_save_data (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg, - uint64_t message_id, - const void *data, - uint16_t data_size) -{ - struct Place *plc = cls; - if (GNUNET_YES != plc->file_save) - return; - - char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (&plc->pub_key); - char *filename = NULL; - GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%" PRIu64 ".part", - dir_social, DIR_SEPARATOR, - "files", DIR_SEPARATOR, - place_pub_str, DIR_SEPARATOR, - GNUNET_ntohll (msg->message_id)); - GNUNET_free (place_pub_str); - if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename)) - { - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "create", filename); - GNUNET_free (filename); - return; - } - - struct GNUNET_DISK_FileHandle * - fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_WRITE, - GNUNET_DISK_PERM_NONE); - if (NULL != fh) - { - if (plc->file_offset != GNUNET_DISK_file_seek - (fh, plc->file_offset, GNUNET_DISK_SEEK_SET)) { - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "seek", filename); - GNUNET_DISK_file_close (fh); - GNUNET_free (filename); - return; - } - GNUNET_DISK_file_write (fh, data, data_size); - GNUNET_DISK_file_close (fh); - GNUNET_free (filename); - } - else - { - GNUNET_free (filename); - GNUNET_break (0); - } - plc->file_offset += data_size; -} - - -/** - * Received end of message to be saved to disk. - * - * Remove .part ending from the filename. - */ -static void -place_recv_save_eom (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg, - uint64_t message_id, - uint8_t is_cancelled) -{ - struct Place *plc = cls; - if (GNUNET_YES != plc->file_save) - return; - - char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (&plc->pub_key); - char *fn = NULL; - GNUNET_asprintf (&fn, "%s%c%s%c%s%c%" PRIu64, - dir_social, DIR_SEPARATOR, - "files", DIR_SEPARATOR, - place_pub_str, DIR_SEPARATOR, - GNUNET_ntohll (msg->message_id)); - GNUNET_free (place_pub_str); - char *fn_part = NULL; - GNUNET_asprintf (&fn_part, "%s.part", fn); - - if (rename (fn_part, fn)) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to rename %s into %s: %s (%d)\n", - fn_part, fn, strerror (errno), errno); - } - - GNUNET_free (fn); - GNUNET_free (fn_part); -} - - -/** - * Initialize place data structure. - */ -static void -place_init (struct Place *plc) -{ - plc->slicer = GNUNET_PSYC_slicer_create (); -} - - -/** - * Add a place to the @e places hash map. - * - * @param ereq - * Entry request. - * - * @return #GNUNET_OK if the place was added - * #GNUNET_NO if the place already exists in the hash map - * #GNUNET_SYSERR on error - */ -static int -place_add (const struct PlaceEnterRequest *ereq) -{ - struct EgoPlacePublicKey ego_place_pub_key = { - .ego_pub_key = ereq->ego_pub_key, - .place_pub_key = ereq->place_pub_key, - }; - struct GNUNET_HashCode ego_place_pub_hash; - GNUNET_CRYPTO_hash (&ego_place_pub_key, sizeof (ego_place_pub_key), &ego_place_pub_hash); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - " ego_place_pub_hash = %s\n", GNUNET_h2s (&ego_place_pub_hash)); - - struct GNUNET_MessageHeader * - place_msg = GNUNET_CONTAINER_multihashmap_get (places, &ego_place_pub_hash); - if (NULL != place_msg) - return GNUNET_NO; - - place_msg = GNUNET_copy_message (&ereq->header); - if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (places, &ego_place_pub_hash, place_msg, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) - { - GNUNET_break (0); - GNUNET_free (place_msg); - return GNUNET_SYSERR; - } - - return GNUNET_OK; -} - -/** - * Add a place to the @e app_places hash map. - * - * @param app_id - * Application ID. - * @param ereq - * Entry request. - * - * @return #GNUNET_OK if the place was added - * #GNUNET_NO if the place already exists in the hash map - * #GNUNET_SYSERR on error - */ -static int -app_place_add (const char *app_id, - const struct PlaceEnterRequest *ereq) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Adding app place to hashmap:\n"); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - " app_id = %s\n", app_id); - - struct GNUNET_HashCode app_id_hash; - GNUNET_CRYPTO_hash (app_id, strlen (app_id) + 1, &app_id_hash); - - struct EgoPlacePublicKey ego_place_pub_key = { - .ego_pub_key = ereq->ego_pub_key, - .place_pub_key = ereq->place_pub_key, - }; - struct GNUNET_HashCode ego_place_pub_hash; - GNUNET_CRYPTO_hash (&ego_place_pub_key, sizeof (ego_place_pub_key), &ego_place_pub_hash); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - " ego_place_pub_hash = %s\n", GNUNET_h2s (&ego_place_pub_hash)); - - struct GNUNET_CONTAINER_MultiHashMap * - app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash); - if (NULL == app_places) - { - app_places = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - GNUNET_CONTAINER_multihashmap_put (apps_places, &app_id_hash, app_places, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - } - - if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (app_places, &ego_place_pub_hash)) - return GNUNET_NO; - - if (GNUNET_SYSERR == place_add (ereq)) - { - return GNUNET_SYSERR; - } - - if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (app_places, &ego_place_pub_hash, NULL, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Save place entry message to disk. - * - * @param app_id - * Application ID. - * @param ereq - * Entry request message. - */ -static int -app_place_save (const char *app_id, - const struct PlaceEnterRequest *ereq) -{ - if (GNUNET_SYSERR == app_place_add (app_id, ereq)) - { - GNUNET_assert (0); - } - - if (NULL == dir_places) - return GNUNET_SYSERR; - - char *ego_pub_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&ereq->ego_pub_key); - char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (&ereq->place_pub_key); - char *filename = NULL; - GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s", - dir_social, DIR_SEPARATOR, - "places", DIR_SEPARATOR, - ego_pub_str, DIR_SEPARATOR, - place_pub_str); - int ret = GNUNET_DISK_directory_create_for_file (filename); - if (GNUNET_OK != ret - || 0 > GNUNET_DISK_fn_write (filename, ereq, ntohs (ereq->header.size), - GNUNET_DISK_PERM_USER_READ - | GNUNET_DISK_PERM_USER_WRITE)) - { - GNUNET_break (0); - ret = GNUNET_SYSERR; - } - GNUNET_free (filename); - - if (ret == GNUNET_OK) - { - GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s%c" "%s", - dir_social, DIR_SEPARATOR, - "apps", DIR_SEPARATOR, - app_id, DIR_SEPARATOR, - ego_pub_str, DIR_SEPARATOR, - place_pub_str); - ret = GNUNET_DISK_directory_create_for_file (filename); - if (GNUNET_OK != ret - || 0 > GNUNET_DISK_fn_write (filename, "", 0, - GNUNET_DISK_PERM_USER_READ - | GNUNET_DISK_PERM_USER_WRITE)) - { - GNUNET_break (0); - ret = GNUNET_SYSERR; - } - GNUNET_free (filename); - } - GNUNET_free (ego_pub_str); - GNUNET_free (place_pub_str); - return ret; -} - - -int -app_place_remove (const char *app_id, - const struct GNUNET_CRYPTO_EcdsaPublicKey *ego_pub_key, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key) -{ - struct GNUNET_HashCode ego_pub_hash; - struct GNUNET_HashCode place_pub_hash; - GNUNET_CRYPTO_hash (ego_pub_key, sizeof (*ego_pub_key), &ego_pub_hash); - GNUNET_CRYPTO_hash (place_pub_key, sizeof (*place_pub_key), &place_pub_hash); - - char *ego_pub_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (ego_pub_key); - char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (place_pub_key); - char *app_place_filename = NULL; - GNUNET_asprintf (&app_place_filename, - "%s%c" "%s%c" "%s%c" "%s%c" "%s", - dir_social, DIR_SEPARATOR, - "apps", DIR_SEPARATOR, - app_id, DIR_SEPARATOR, - ego_pub_str, DIR_SEPARATOR, - place_pub_str); - GNUNET_free (ego_pub_str); - GNUNET_free (place_pub_str); - - struct GNUNET_HashCode app_id_hash; - GNUNET_CRYPTO_hash (app_id, strlen (app_id) + 1, &app_id_hash); - - struct GNUNET_CONTAINER_MultiHashMap * - app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash); - - if (NULL != app_places) - GNUNET_CONTAINER_multihashmap_remove (app_places, &place_pub_hash, NULL); - - int ret = GNUNET_OK; - - if (0 != unlink (app_place_filename)) - { - GNUNET_break (0); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error removing app place file: %s: %s (%d)\n", - app_place_filename, strerror (errno), errno); - ret = GNUNET_SYSERR; - } - GNUNET_free (app_place_filename); - - return ret; -} - - -/** - * Enter place as host. - * - * @param hreq - * Host entry request. - * @param[out] ret_hst - * Returned Host struct. - * - * @return #GNUNET_YES if the host entered the place just now, - * #GNUNET_NO if the place is already entered, - * #GNUNET_SYSERR if place_pub_key was set - * but its private key was not found - */ -static int -host_enter (const struct HostEnterRequest *hreq, struct Host **ret_hst) -{ - int ret = GNUNET_NO; - struct GNUNET_HashCode place_pub_hash; - GNUNET_CRYPTO_hash (&hreq->place_pub_key, sizeof (hreq->place_pub_key), - &place_pub_hash); - struct Host *hst = GNUNET_CONTAINER_multihashmap_get (hosts, &place_pub_hash); - - if (NULL == hst) - { - hst = GNUNET_new (struct Host); - hst->policy = hreq->policy; - hst->join_reqs = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - hst->relay_msgs = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - - struct Place *plc = &hst->place; - place_init (plc); - plc->is_host = GNUNET_YES; - plc->pub_key = hreq->place_pub_key; - plc->pub_key_hash = place_pub_hash; - - GNUNET_CONTAINER_multihashmap_put (hosts, &plc->pub_key_hash, plc, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - hst->master = GNUNET_PSYC_master_start (cfg, &hreq->place_key, hst->policy, - &psyc_master_started, - &psyc_recv_join_request, - &psyc_recv_message, NULL, hst); - plc->channel = GNUNET_PSYC_master_get_channel (hst->master); - ret = GNUNET_YES; - } - - if (NULL != ret_hst) - *ret_hst = hst; - return ret; -} - - -static int -msg_proc_parse (const struct MsgProcRequest *mpreq, - uint32_t *flags, - const char **method_prefix, - struct GNUNET_HashCode *method_hash) -{ - ssize_t method_size = ntohs (mpreq->header.size) - sizeof (*mpreq); - uint16_t offset; - - if (method_size < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "MsgProcRequest has invalid size\n"); - return GNUNET_SYSERR; - } - - offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &mpreq[1], - method_size, - 1, - method_prefix); - if (0 == offset || offset != method_size || *method_prefix == NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "MsgProcRequest contains invalid method\n"); - return GNUNET_SYSERR; - } - GNUNET_CRYPTO_hash (*method_prefix, (size_t) method_size, method_hash); - *flags = ntohl (mpreq->flags); - return GNUNET_OK; -} - - -void -app_notify_place (const struct GNUNET_MessageHeader *msg, - struct GNUNET_SERVICE_Client *client) -{ - struct AppPlaceMessage *amsg; - struct GNUNET_MQ_Envelope *env; - uint16_t msg_size = ntohs (msg->size); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Sending place notification of type %u to client.\n", - client, ntohs (msg->type)); - switch (ntohs (msg->type)) - { - case GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER: - { - struct HostEnterRequest *hreq = (struct HostEnterRequest *) msg; - if (msg_size < sizeof (struct HostEnterRequest)) - return; - env = GNUNET_MQ_msg (amsg, - GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE); - // FIXME: also notify about not entered places - amsg->place_state = GNUNET_SOCIAL_PLACE_STATE_ENTERED; - amsg->is_host = GNUNET_YES; - amsg->ego_pub_key = hreq->ego_pub_key; - amsg->place_pub_key = hreq->place_pub_key; - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), - env); - break; - } - case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER: - { - if (msg_size < sizeof (struct GuestEnterRequest)) - return; - struct GuestEnterRequest *greq = (struct GuestEnterRequest *) msg; - env = GNUNET_MQ_msg (amsg, - GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE); - // FIXME: also notify about not entered places - amsg->place_state = GNUNET_SOCIAL_PLACE_STATE_ENTERED; - amsg->is_host = GNUNET_NO; - amsg->ego_pub_key = greq->ego_pub_key; - amsg->place_pub_key = greq->place_pub_key; - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), - env); - break; - } - default: - return; - } -} - - -void -app_notify_place_end (struct GNUNET_SERVICE_Client *client) -{ - struct GNUNET_MQ_Envelope *env; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Sending end of place list notification to client\n", - client); - env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE_END); - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), - env); -} - - -void -app_notify_ego (struct Ego *ego, struct GNUNET_SERVICE_Client *client) -{ - struct AppEgoMessage *emsg; - struct GNUNET_MQ_Envelope *env; - size_t name_size = strlen (ego->name) + 1; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Sending ego notification to client: %s\n", - client, ego->name); - env = GNUNET_MQ_msg_extra (emsg, - name_size, - GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO); - GNUNET_CRYPTO_ecdsa_key_get_public (&ego->key, &emsg->ego_pub_key); - GNUNET_memcpy (&emsg[1], ego->name, name_size); - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), - env); -} - - -void -app_notify_ego_end (struct GNUNET_SERVICE_Client *client) -{ - struct GNUNET_MQ_Envelope *env; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Sending end of ego list notification to client\n", - client); - env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO_END); - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), - env); -} - - -int -app_place_entry_notify (void *cls, const struct GNUNET_HashCode *key, void *value) -{ - struct GNUNET_MessageHeader * - msg = GNUNET_CONTAINER_multihashmap_get (places, key); - if (NULL != msg) - app_notify_place (msg, cls); - return GNUNET_YES; -} - - -int -ego_entry (void *cls, const struct GNUNET_HashCode *key, void *value) -{ - app_notify_ego (value, cls); - return GNUNET_YES; -} - - -static int -check_client_msg_proc_set (void *cls, - const struct MsgProcRequest *mpreq) -{ - return GNUNET_OK; -} - - -/** - * Handle a client setting message proccesing flags for a method prefix. - */ -static void -handle_client_msg_proc_set (void *cls, - const struct MsgProcRequest *mpreq) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - struct Place *plc = c->place; - if (NULL == plc) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - - const char *method_prefix = NULL; - uint32_t flags = 0; - struct GNUNET_HashCode method_hash; - - if (GNUNET_OK != - msg_proc_parse (mpreq, &flags, &method_prefix, &method_hash)) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } -#if 0 - GNUNET_PSYC_slicer_method_remove (plc->slicer, method_prefix, - place_recv_relay_method, - place_recv_relay_modifier, - place_recv_relay_data, - place_recv_relay_eom); - GNUNET_PSYC_slicer_method_remove (plc->slicer, method_prefix, - place_recv_save_method, - NULL, - place_recv_save_data, - place_recv_save_eom); -#endif - if (flags & GNUNET_SOCIAL_MSG_PROC_RELAY) - { - GNUNET_PSYC_slicer_method_add (plc->slicer, method_prefix, NULL, - place_recv_relay_method, - place_recv_relay_modifier, - place_recv_relay_data, - place_recv_relay_eom, - plc); - } - if (flags & GNUNET_SOCIAL_MSG_PROC_SAVE) - { - GNUNET_PSYC_slicer_method_add (plc->slicer, method_prefix, NULL, - place_recv_save_method, - NULL, - place_recv_save_data, - place_recv_save_eom, - plc); - } - - /** @todo Save flags to be able to resume relaying/saving after restart */ - - GNUNET_SERVICE_client_continue (client); -} - - -/** - * Handle a connecting client requesting to clear all relay rules. - */ -static void -handle_client_msg_proc_clear (void *cls, - const struct GNUNET_MessageHeader *msg) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - struct Place *plc = c->place; - if (NULL == plc) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - - GNUNET_PSYC_slicer_clear (plc->slicer); - - GNUNET_SERVICE_client_continue (client); -} - - -static int -check_client_host_enter (void *cls, - const struct HostEnterRequest *hr) -{ - return GNUNET_OK; -} - - -/** - * Handle a connecting client entering a place as host. - */ -static void -handle_client_host_enter (void *cls, - const struct HostEnterRequest *hr) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - struct HostEnterRequest * - hreq = (struct HostEnterRequest *) GNUNET_copy_message (&hr->header); - - uint8_t app_id_size = ntohs (hreq->header.size) - sizeof (*hreq); - const char *app_id = NULL; - uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &hreq[1], - app_id_size, 1, &app_id); - if (0 == offset || offset != app_id_size || app_id == NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "offset = %u, app_id_size = %u, app_id = %s\n", - offset, app_id_size, app_id); - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - - struct Host *hst = NULL; - struct Place *plc = NULL; - int ret = GNUNET_OK; - - struct GNUNET_CRYPTO_EddsaPublicKey empty_pub_key; - memset (&empty_pub_key, 0, sizeof (empty_pub_key)); - - if (0 == memcmp (&hreq->place_pub_key, &empty_pub_key, sizeof (empty_pub_key))) - { // no public key set: create new private key & save the place - struct GNUNET_CRYPTO_EddsaPrivateKey * - place_key = GNUNET_CRYPTO_eddsa_key_create (); - hreq->place_key = *place_key; - GNUNET_CRYPTO_eddsa_key_get_public (place_key, &hreq->place_pub_key); - GNUNET_CRYPTO_eddsa_key_clear (place_key); - GNUNET_free (place_key); - - app_place_save (app_id, (const struct PlaceEnterRequest *) hreq); - } - - switch (host_enter (hreq, &hst)) - { - case GNUNET_YES: - plc = c->place = &hst->place; - plc->host = hst; - break; - - case GNUNET_NO: - { - plc = c->place = &hst->place; - plc->host = hst; - client_send_host_enter_ack (client, hst, GNUNET_OK); - break; - } - case GNUNET_SYSERR: - ret = GNUNET_SYSERR; - } - - if (ret != GNUNET_SYSERR) - { - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Client connected as host to place %s.\n", - hst, GNUNET_h2s (&plc->pub_key_hash)); - - struct ClientListItem *cli = GNUNET_new (struct ClientListItem); - cli->client = client; - GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli); - c->place = plc; - app_notify_place (&hreq->header, client); - } - - GNUNET_CRYPTO_eddsa_key_clear (&hreq->place_key); - GNUNET_free (hreq); - - if (GNUNET_OK == ret) - GNUNET_SERVICE_client_continue (client); - else - GNUNET_SERVICE_client_drop (client); -} - - -/** - * Enter place as guest. - * - * @param greq - * Guest entry request. - * @param[out] ret_gst - * Returned Guest struct. - * - * @return #GNUNET_YES if the guest entered the place just now, - * #GNUNET_NO if the place is already entered, - * #GNUNET_SYSERR on error. - */ -static int -guest_enter (const struct GuestEnterRequest *greq, struct Guest **ret_gst) -{ - int ret = GNUNET_NO; - uint16_t greq_size = ntohs (greq->header.size); - - struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key = greq->ego_pub_key; - struct GNUNET_HashCode ego_pub_hash; - GNUNET_CRYPTO_hash (&ego_pub_key, sizeof (ego_pub_key), &ego_pub_hash); - struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash); - - if (NULL == ego) - { - return GNUNET_SYSERR; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "entering as guest\n"); - struct GNUNET_HashCode place_pub_hash; - GNUNET_CRYPTO_hash (&greq->place_pub_key, sizeof (greq->place_pub_key), - &place_pub_hash); - - struct GNUNET_CONTAINER_MultiHashMap * - plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests, &place_pub_hash); - struct Guest *gst = NULL; - int new_guest; - - if (NULL != plc_gst) - gst = GNUNET_CONTAINER_multihashmap_get (plc_gst, &ego_pub_hash); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "plc_gst = %p, gst = %p\n", - plc_gst, - gst); - - if (NULL == gst) - { - gst = GNUNET_new (struct Guest); - new_guest = GNUNET_YES; - } - else new_guest = GNUNET_NO; - - if (NULL == gst->slave) - { - gst->origin = greq->origin; - gst->relay_count = ntohl (greq->relay_count); - - uint16_t len; - uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq); - const char *app_id = (const char *) &greq[1]; - const char *p = app_id; - - len = strnlen (app_id, remaining); - if (len == remaining) - { - GNUNET_free (gst); - GNUNET_break (0); - return GNUNET_SYSERR; - } - p += len + 1; - remaining -= len + 1; - - const struct GNUNET_PeerIdentity *relays = NULL; - uint16_t relay_size = gst->relay_count * sizeof (*relays); - if (remaining < relay_size) - { - GNUNET_free (gst); - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (0 < relay_size) - relays = (const struct GNUNET_PeerIdentity *) p; - p += relay_size; - remaining -= relay_size; - - struct GNUNET_PSYC_Message *join_msg = NULL; - uint16_t join_msg_size = 0; - - if (sizeof (struct GNUNET_MessageHeader) <= remaining) - { - join_msg = (struct GNUNET_PSYC_Message *) p; - join_msg_size = ntohs (join_msg->header.size); - p += join_msg_size; - remaining -= join_msg_size; - } - if (0 != remaining) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%zu + %u + %u != %u\n", - sizeof (*greq), relay_size, join_msg_size, greq_size); - GNUNET_free (gst); - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (0 < relay_size) - { - gst->relays = GNUNET_malloc (relay_size); - GNUNET_memcpy (gst->relays, relays, relay_size); - } - - gst->join_flags = ntohl (greq->flags); - - struct Place *plc = &gst->place; - place_init (plc); - plc->is_host = GNUNET_NO; - plc->pub_key = greq->place_pub_key; - plc->pub_key_hash = place_pub_hash; - plc->ego_pub_key = ego_pub_key; - plc->ego_pub_hash = ego_pub_hash; - plc->ego_key = ego->key; - - if (NULL == plc_gst) - { - plc_gst = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); - (void) GNUNET_CONTAINER_multihashmap_put (place_guests, &plc->pub_key_hash, plc_gst, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - } - if (GNUNET_YES == new_guest) - { - (void) GNUNET_CONTAINER_multihashmap_put (plc_gst, &plc->ego_pub_hash, gst, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - (void) GNUNET_CONTAINER_multihashmap_put (guests, &plc->pub_key_hash, gst, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - - } - gst->slave - = GNUNET_PSYC_slave_join (cfg, &plc->pub_key, &plc->ego_key, - gst->join_flags, &gst->origin, - gst->relay_count, gst->relays, - &psyc_recv_message, NULL, - &psyc_slave_connected, - &psyc_recv_join_dcsn, - gst, join_msg); - plc->channel = GNUNET_PSYC_slave_get_channel (gst->slave); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "slave entered channel %p\n", - plc->channel); - ret = GNUNET_YES; - } - - // TODO: explain to automatic code scanners why free(gst) not necessary - if (NULL != ret_gst) - *ret_gst = gst; - return ret; -} - - -static int -client_guest_enter (struct Client *c, - const struct GuestEnterRequest *greq) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "client_guest_enter\n"); - struct GNUNET_PSYC_CountersResultMessage *result_msg; - struct GNUNET_MQ_Envelope *env; - struct GNUNET_SERVICE_Client *client = c->client; - uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq); - const char *app_id = NULL; - uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &greq[1], - remaining, 1, &app_id); - struct Guest *gst = NULL; - struct Place *plc = NULL; - - if (0 == offset) - { - return GNUNET_SYSERR; - } - switch (guest_enter (greq, &gst)) - { - case GNUNET_YES: - { - plc = c->place = &gst->place; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "guest entered successfully to local place %s\n", - GNUNET_h2s (&plc->pub_key_hash)); - plc->guest = gst; - app_place_save (app_id, (const struct PlaceEnterRequest *) greq); - app_notify_place (&greq->header, client); - break; - } - case GNUNET_NO: - { - plc = c->place = &gst->place; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "guest re-entered successfully to local place %s\n", - GNUNET_h2s (&plc->pub_key_hash)); - plc->guest = gst; - env = GNUNET_MQ_msg (result_msg, - GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK); - result_msg->result_code = htonl (GNUNET_OK); - result_msg->max_message_id = GNUNET_htonll (plc->max_message_id); - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), - env); - if (NULL != gst->join_dcsn) - { - env = GNUNET_MQ_msg_copy (&gst->join_dcsn->header); - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), - env); - } - break; - } - case GNUNET_SYSERR: - { - return GNUNET_SYSERR; - } - } - - struct ClientListItem *cli = GNUNET_new (struct ClientListItem); - cli->client = client; - GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli); - return GNUNET_OK; -} - - -static int -check_client_guest_enter (void *cls, - const struct GuestEnterRequest *greq) -{ - return GNUNET_OK; -} - - -/** - * Handle a connecting client entering a place as guest. - */ -static void -handle_client_guest_enter (void *cls, - const struct GuestEnterRequest *greq) -{ - struct Client *c = cls; - - if (GNUNET_SYSERR == client_guest_enter (c, greq)) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (c->client); - return; - } - GNUNET_SERVICE_client_continue (c->client); -} - - -struct GuestEnterByNameClosure -{ - struct Client *client; - char *app_id; - char *password; - struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; - struct GNUNET_MessageHeader *join_msg; -}; - - -/** - * Result of a GNS name lookup for entering a place. - * - * @see GNUNET_SOCIAL_guest_enter_by_name - */ -static void -gns_result_guest_enter (void *cls, uint32_t rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct GuestEnterByNameClosure *gcls = cls; - struct Client *c = gcls->client; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p GNS result: %u records.\n", - c, rd_count); - - const struct GNUNET_GNSRECORD_PlaceData * - rec = (const struct GNUNET_GNSRECORD_PlaceData *) rd->data; - - if (0 == rd_count || rd->data_size < sizeof (*rec)) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (c->client); - return; - } - - uint16_t relay_count = ntohl (rec->relay_count); - struct GNUNET_PeerIdentity *relays = NULL; - - if (0 < relay_count) - { - if (rd->data_size == sizeof (*rec) + relay_count * sizeof (struct GNUNET_PeerIdentity)) - { - relays = (struct GNUNET_PeerIdentity *) &rec[1]; - } - else - { - relay_count = 0; - GNUNET_break_op (0); - } - } - - uint16_t app_id_size = strlen (gcls->app_id) + 1; - uint16_t relay_size = relay_count * sizeof (*relays); - uint16_t join_msg_size = 0; - if (NULL != gcls->join_msg) - join_msg_size = ntohs (gcls->join_msg->size); - uint16_t greq_size = sizeof (struct GuestEnterRequest) - + app_id_size + relay_size + join_msg_size; - struct GuestEnterRequest *greq = GNUNET_malloc (greq_size); - greq->header.size = htons (greq_size); - greq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER); - greq->ego_pub_key = gcls->ego_pub_key; - greq->place_pub_key = rec->place_pub_key; - greq->origin = rec->origin; - greq->relay_count = rec->relay_count; - - void *p = &greq[1]; - GNUNET_memcpy (p, gcls->app_id, app_id_size); - p += app_id_size; - GNUNET_memcpy (p, relays, relay_size); - p += relay_size; - GNUNET_memcpy (p, gcls->join_msg, join_msg_size); - - client_guest_enter (c, greq); - - GNUNET_free (gcls->app_id); - if (NULL != gcls->password) - GNUNET_free (gcls->password); - if (NULL != gcls->join_msg) - GNUNET_free (gcls->join_msg); - GNUNET_free (gcls); - GNUNET_free (greq); -} - - -static int -check_client_guest_enter_by_name (void *cls, - const struct GuestEnterByNameRequest *greq) -{ - return GNUNET_OK; -} - - -/** - * Handle a connecting client entering a place as guest using a GNS address. - * - * Look up GNS address and generate a GuestEnterRequest from that. - */ -static void -handle_client_guest_enter_by_name (void *cls, - const struct GuestEnterByNameRequest *greq) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - - struct GuestEnterByNameClosure *gcls = GNUNET_malloc (sizeof (*gcls)); - gcls->client = c; - gcls->ego_pub_key = greq->ego_pub_key; - - const char *p = (const char *) &greq[1]; - const char *app_id = NULL, *password = NULL, *gns_name = NULL; - uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq); - uint16_t offset = GNUNET_STRINGS_buffer_tokenize (p, remaining, 3, - &app_id, - &gns_name, - &password); - p += offset; - remaining -= offset; - - if (0 != offset && sizeof (*gcls->join_msg) <= remaining) - { - gcls->join_msg = GNUNET_copy_message ((struct GNUNET_MessageHeader *) p); - remaining -= ntohs (gcls->join_msg->size); - } - - if (0 == offset || 0 != remaining) - { - if (NULL != gcls->join_msg) - GNUNET_free (gcls->join_msg); - GNUNET_free (gcls); - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - - uint16_t app_id_size = strlen (app_id) + 1; - gcls->app_id = GNUNET_malloc (app_id_size); - GNUNET_memcpy (gcls->app_id, app_id, app_id_size); - - uint16_t password_size = strlen (password); - if (0 < password_size++) - { - gcls->password = GNUNET_malloc (password_size); - GNUNET_memcpy (gcls->password, password, password_size); - } - - GNUNET_GNS_lookup (gns, gns_name, - &greq->ego_pub_key, - GNUNET_GNSRECORD_TYPE_PLACE, - GNUNET_GNS_LO_DEFAULT, - &gns_result_guest_enter, gcls); - GNUNET_SERVICE_client_continue (client); -} - - -static int -check_client_app_connect (void *cls, - const struct AppConnectRequest *creq) -{ - return GNUNET_OK; -} - - -/** - * Handle application connection. - */ -static void -handle_client_app_connect (void *cls, - const struct AppConnectRequest *creq) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - ssize_t app_id_size = ntohs (creq->header.size) - sizeof (*creq); - const char *app_id = NULL; - uint16_t offset; - - if (app_id_size < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "AppConnectRequest has invalid size\n"); - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - - offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &creq[1], - (size_t) app_id_size, - 1, - &app_id); - if (0 == offset || offset != app_id_size) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "AppConnectRequest contains invalid app ID\n"); - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - - struct GNUNET_HashCode app_id_hash; - GNUNET_CRYPTO_hash (app_id, (size_t) app_id_size, &app_id_hash); - - GNUNET_CONTAINER_multihashmap_iterate (egos, ego_entry, client); - app_notify_ego_end (client); - - struct GNUNET_CONTAINER_MultiHashMap * - app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash); - if (NULL != app_places) - GNUNET_CONTAINER_multihashmap_iterate (app_places, app_place_entry_notify, client); - app_notify_place_end (client); - - struct ClientListItem *cli = GNUNET_new (struct ClientListItem); - cli->client = client; - struct Application *app = GNUNET_CONTAINER_multihashmap_get (apps, - &app_id_hash); - if (NULL == app) { - app = GNUNET_malloc (sizeof (*app)); - (void) GNUNET_CONTAINER_multihashmap_put (apps, &app_id_hash, app, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - } - GNUNET_CONTAINER_DLL_insert (app->clients_head, app->clients_tail, cli); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Application %s connected.\n", app, app_id); - - c->app_id = GNUNET_malloc ((size_t) app_id_size); - GNUNET_memcpy (c->app_id, app_id, (size_t) app_id_size); - - GNUNET_SERVICE_client_continue (client); -} - - -/** - * Handle application detach request. - */ -static void -handle_client_app_detach (void *cls, - const struct AppDetachRequest *req) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - - int ret = app_place_remove (c->app_id, &req->ego_pub_key, &req->place_pub_key); - client_send_result (client, req->op_id, ret, NULL, 0); - - GNUNET_SERVICE_client_continue (client); -} - - -static void -place_leave_cb (void *cls) -{ - struct Place *plc = cls; - - place_send_leave_ack (plc); - (GNUNET_YES == plc->is_host) - ? cleanup_host ((struct Host *) plc) - : cleanup_guest ((struct Guest *) plc); -} - - -/** - * Handle application leave request. - */ -static void -handle_client_place_leave (void *cls, - const struct GNUNET_MessageHeader *msg) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - struct Place *plc = c->place; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "got leave request from %s for place %s", - plc->is_host? "host" : "slave", - GNUNET_h2s (&plc->pub_key_hash)); - if (NULL == plc) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - - if (GNUNET_YES != plc->is_disconnecting) - { - plc->is_disconnecting = GNUNET_YES; - if (plc->is_host) - { - struct Host *host = plc->host; - GNUNET_assert (NULL != host); - GNUNET_PSYC_master_stop (host->master, GNUNET_NO, &place_leave_cb, plc); - } - else - { - struct Guest *guest = plc->guest; - GNUNET_assert (NULL != guest); - GNUNET_PSYC_slave_part (guest->slave, GNUNET_NO, &place_leave_cb, plc); - } - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "got leave request but place is already leaving\n"); - } - GNUNET_SERVICE_client_continue (client); -} - - -struct JoinDecisionClosure -{ - int32_t is_admitted; - struct GNUNET_PSYC_Message *msg; -}; - - -/** - * Iterator callback for responding to join requests. - */ -static int -psyc_send_join_decision (void *cls, const struct GNUNET_HashCode *pub_key_hash, - void *value) -{ - struct JoinDecisionClosure *jcls = cls; - struct GNUNET_PSYC_JoinHandle *jh = value; - // FIXME: add relays - GNUNET_PSYC_join_decision (jh, jcls->is_admitted, 0, NULL, jcls->msg); - return GNUNET_YES; -} - - -static int -check_client_join_decision (void *cls, - const struct GNUNET_PSYC_JoinDecisionMessage *dcsn) -{ - return GNUNET_OK; -} - - -/** - * Handle an entry decision from a host client. - */ -static void -handle_client_join_decision (void *cls, - const struct GNUNET_PSYC_JoinDecisionMessage *dcsn) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - struct Place *plc = c->place; - if (NULL == plc || GNUNET_YES != plc->is_host) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - struct Host *hst = plc->host; - - struct JoinDecisionClosure jcls; - jcls.is_admitted = ntohl (dcsn->is_admitted); - jcls.msg - = (sizeof (*dcsn) + sizeof (*jcls.msg) <= ntohs (dcsn->header.size)) - ? (struct GNUNET_PSYC_Message *) &dcsn[1] - : NULL; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "jcls.msg = %p\n", - jcls.msg); - struct GNUNET_HashCode slave_pub_hash; - GNUNET_CRYPTO_hash (&dcsn->slave_pub_key, sizeof (dcsn->slave_pub_key), - &slave_pub_hash); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Got join decision (%d) from client for place %s..\n", - hst, jcls.is_admitted, GNUNET_h2s (&plc->pub_key_hash)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p ..and slave %s.\n", - hst, GNUNET_h2s (&slave_pub_hash)); - - GNUNET_CONTAINER_multihashmap_get_multiple (hst->join_reqs, &slave_pub_hash, - &psyc_send_join_decision, &jcls); - GNUNET_CONTAINER_multihashmap_remove_all (hst->join_reqs, &slave_pub_hash); - - GNUNET_SERVICE_client_continue (client); -} - - -/** - * Send acknowledgement to a client. - * - * Sent after a message fragment has been passed on to multicast. - * - * @param plc The place struct for the client. - */ -static void -send_message_ack (struct Place *plc, struct GNUNET_SERVICE_Client *client) -{ - struct GNUNET_MQ_Envelope *env; - - env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK); - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), - env); -} - - -/** - * Proceed to the next message part in the transmission queue. - * - * @param plc - * Place where the transmission is going on. - * @param tmit_msg - * Currently transmitted message. - * @param tmit_frag - * Currently transmitted message fragment. - * - * @return @a tmit_frag, or NULL if reached the end of fragment. - */ -static struct FragmentTransmitQueue * -psyc_transmit_queue_next_part (struct Place *plc, - struct MessageTransmitQueue *tmit_msg, - struct FragmentTransmitQueue *tmit_frag) -{ - uint16_t psize = ntohs (tmit_frag->next_part->size); - if ((char *) tmit_frag->next_part + psize - ((char *) &tmit_frag[1]) - < tmit_frag->size) - { - tmit_frag->next_part - = (struct GNUNET_MessageHeader *) ((char *) tmit_frag->next_part + psize); - } - else /* Reached end of current fragment. */ - { - if (NULL != tmit_frag->client) - send_message_ack (plc, tmit_frag->client); - GNUNET_CONTAINER_DLL_remove (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag); - GNUNET_free (tmit_frag); - tmit_frag = NULL; - } - return tmit_frag; -} - - -/** - * Proceed to next message in transmission queue. - * - * @param plc - * Place where the transmission is going on. - * @param tmit_msg - * Currently transmitted message. - * - * @return The next message in queue, or NULL if queue is empty. - */ -static struct MessageTransmitQueue * -psyc_transmit_queue_next_msg (struct Place *plc, - struct MessageTransmitQueue *tmit_msg) -{ - GNUNET_CONTAINER_DLL_remove (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg); - GNUNET_free (tmit_msg); - return plc->tmit_msgs_head; -} - - -/** - * Callback for data transmission to PSYC. - */ -static int -psyc_transmit_notify_data (void *cls, uint16_t *data_size, void *data) -{ - struct Place *plc = cls; - struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head; - GNUNET_assert (NULL != tmit_msg); - struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head; - if (NULL == tmit_frag) - { /* Rest of the message have not arrived yet, pause transmission */ - *data_size = 0; - return GNUNET_NO; - } - struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part; - if (NULL == pmsg) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p psyc_transmit_notify_data: nothing to send.\n", plc); - *data_size = 0; - return GNUNET_NO; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p psyc_transmit_notify_data()\n", plc); - GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg); - - uint16_t ptype = ntohs (pmsg->type); - uint16_t pdata_size = ntohs (pmsg->size) - sizeof (*pmsg); - int ret; - - switch (ptype) - { - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA: - if (*data_size < pdata_size) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p psyc_transmit_notify_data: buffer size too small for data.\n", plc); - *data_size = 0; - return GNUNET_NO; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p psyc_transmit_notify_data: sending %u bytes.\n", - plc, pdata_size); - - *data_size = pdata_size; - GNUNET_memcpy (data, &pmsg[1], *data_size); - ret = GNUNET_NO; - break; - - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: - *data_size = 0; - ret = GNUNET_YES; - break; - - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL: - *data_size = 0; - ret = GNUNET_SYSERR; - break; - - default: - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "%p psyc_transmit_notify_data: unexpected message part of type %u.\n", - plc, ptype); - ret = GNUNET_SYSERR; - } - - if (GNUNET_SYSERR == ret && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL != ptype) - { - *data_size = 0; - tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg); - GNUNET_SERVICE_client_drop (tmit_frag->client); - GNUNET_SCHEDULER_add_now (&cleanup_place, plc); - return ret; - } - else - { - tmit_frag = psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag); - if (NULL != tmit_frag) - { - struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part; - ptype = ntohs (pmsg->type); - switch (ptype) - { - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: - ret = GNUNET_YES; - break; - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL: - ret = GNUNET_SYSERR; - break; - } - switch (ptype) - { - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL: - tmit_frag = psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag); - } - } - - if (NULL == tmit_msg->frags_head - && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype) - { /* Reached end of current message. */ - tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg); - } - } - - if (ret != GNUNET_NO) - { - if (NULL != tmit_msg) - { - psyc_transmit_message (plc); - } - /* FIXME: handle partial message (when still in_transmit) */ - } - return ret; -} - - -/** - * Callback for modifier transmission to PSYC. - */ -static int -psyc_transmit_notify_mod (void *cls, uint16_t *data_size, void *data, - uint8_t *oper, uint32_t *full_value_size) -{ - struct Place *plc = cls; - struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head; - GNUNET_assert (NULL != tmit_msg); - struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head; - if (NULL == tmit_frag) - { /* Rest of the message have not arrived yet, pause transmission */ - *data_size = 0; - return GNUNET_NO; - } - struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part; - if (NULL == pmsg) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p psyc_transmit_notify_mod: nothing to send.\n", plc); - *data_size = 0; - return GNUNET_NO; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p psyc_transmit_notify_mod()\n", plc); - GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg); - - uint16_t ptype = ntohs (pmsg->type); - int ret; - - switch (ptype) - { - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: - { - if (NULL == oper) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%p psyc_transmit_notify_mod: oper is NULL.\n", plc); - ret = GNUNET_SYSERR; - break; - } - struct GNUNET_PSYC_MessageModifier * - pmod = (struct GNUNET_PSYC_MessageModifier *) tmit_frag->next_part; - uint16_t mod_size = ntohs (pmod->header.size) - sizeof (*pmod); - - if (*data_size < mod_size) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc); - *data_size = 0; - return GNUNET_NO; - } - - *full_value_size = ntohl (pmod->value_size); - *oper = pmod->oper; - *data_size = mod_size; - GNUNET_memcpy (data, &pmod[1], mod_size); - ret = GNUNET_NO; - break; - } - - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: - { - if (NULL != oper) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%p psyc_transmit_notify_mod: oper is not NULL.\n", plc); - ret = GNUNET_SYSERR; - break; - } - uint16_t mod_size = ntohs (pmsg->size) - sizeof (*pmsg); - if (*data_size < mod_size) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc); - *data_size = 0; - return GNUNET_NO; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p psyc_transmit_notify_mod: sending %u bytes.\n", plc, mod_size); - - *data_size = mod_size; - GNUNET_memcpy (data, &pmsg[1], *data_size); - ret = GNUNET_NO; - break; - } - - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA: - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL: - *data_size = 0; - ret = GNUNET_YES; - break; - - default: - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "%p psyc_transmit_notify_mod: unexpected message part of type %u.\n", - plc, ptype); - ret = GNUNET_SYSERR; - } - - if (GNUNET_SYSERR == ret) - { - *data_size = 0; - ret = GNUNET_SYSERR; - tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg); - GNUNET_SERVICE_client_drop (tmit_frag->client); - GNUNET_SCHEDULER_add_now (&cleanup_place, plc); - } - else - { - if (GNUNET_YES != ret) - psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag); - - if (NULL == tmit_msg->frags_head - && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype) - { /* Reached end of current message. */ - tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg); - } - } - return ret; -} - -/** - * Callback for data transmission from a host to PSYC. - */ -static int -host_transmit_notify_data (void *cls, uint16_t *data_size, void *data) -{ - int ret = psyc_transmit_notify_data (cls, data_size, data); - - if (GNUNET_NO != ret) - { - struct Host *hst = cls; - hst->tmit_handle = NULL; - } - return ret; -} - - -/** - * Callback for the transmit functions of multicast. - */ -static int -guest_transmit_notify_data (void *cls, uint16_t *data_size, void *data) -{ - int ret = psyc_transmit_notify_data (cls, data_size, data); - - if (GNUNET_NO != ret) - { - struct Guest *gst = cls; - gst->tmit_handle = NULL; - } - return ret; -} - - -/** - * Callback for modifier transmission from a host to PSYC. - */ -static int -host_transmit_notify_mod (void *cls, uint16_t *data_size, void *data, - uint8_t *oper, uint32_t *full_value_size) -{ - int ret = psyc_transmit_notify_mod (cls, data_size, data, - oper, full_value_size); - if (GNUNET_SYSERR == ret) - { - struct Host *hst = cls; - hst->tmit_handle = NULL; - } - return ret; -} - - -/** - * Callback for modifier transmission from a guest to PSYC. - */ -static int -guest_transmit_notify_mod (void *cls, uint16_t *data_size, void *data, - uint8_t *oper, uint32_t *full_value_size) -{ - int ret = psyc_transmit_notify_mod (cls, data_size, data, - oper, full_value_size); - if (GNUNET_SYSERR == ret) - { - struct Guest *gst = cls; - gst->tmit_handle = NULL; - } - return ret; -} - - -/** - * Get method part of next message from transmission queue. - * - * @param plc - * Place - * - * @return #GNUNET_OK on success - * #GNUNET_NO if there are no more messages in queue. - * #GNUNET_SYSERR if the next message is malformed. - */ -static struct GNUNET_PSYC_MessageMethod * -psyc_transmit_queue_next_method (struct Place *plc) -{ - struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head; - if (NULL == tmit_msg) - return GNUNET_NO; - - struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head; - if (NULL == tmit_frag) - { - GNUNET_break (0); - return GNUNET_NO; - } - - struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part; - if (NULL == pmsg - || GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD != ntohs (pmsg->type)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "%p psyc_transmit_queue_next_method: unexpected message part of type %u.\n", - plc, NULL != pmsg ? ntohs (pmsg->type) : 0); - GNUNET_break (0); - return NULL; - } - - uint16_t psize = ntohs (pmsg->size); - struct GNUNET_PSYC_MessageMethod * - pmeth = (struct GNUNET_PSYC_MessageMethod *) GNUNET_copy_message (pmsg); - - if (psize < sizeof (*pmeth) + 1 || '\0' != *((char *) pmeth + psize - 1)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "%p psyc_transmit_queue_next_method: invalid method name.\n", - plc); - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "%zu <= %u || NUL != %u\n", - sizeof (*pmeth), psize, *((char *) pmeth + psize - 1)); - GNUNET_break (0); - GNUNET_free (pmeth); - return NULL; - } - - psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag); - return pmeth; -} - - -/** - * Transmit the next message in queue from the host to the PSYC channel. - */ -static int -psyc_master_transmit_message (struct Host *hst) -{ - struct Place *plc = &hst->place; - - if (NULL == hst->tmit_handle) - { - struct GNUNET_PSYC_MessageMethod * - pmeth = psyc_transmit_queue_next_method (plc); - if (NULL == pmeth) - return GNUNET_SYSERR; - - hst->tmit_handle = (void *) &hst->tmit_handle; - struct GNUNET_PSYC_MasterTransmitHandle * - tmit_handle = GNUNET_PSYC_master_transmit (hst->master, (const char *) &pmeth[1], - &host_transmit_notify_mod, - &host_transmit_notify_data, hst, - pmeth->flags); - if (NULL != hst->tmit_handle) - hst->tmit_handle = tmit_handle; - GNUNET_free (pmeth); - } - else - { - GNUNET_PSYC_master_transmit_resume (hst->tmit_handle); - } - return GNUNET_OK; -} - - -/** - * Transmit the next message in queue from a guest to the PSYC channel. - */ -static int -psyc_slave_transmit_message (struct Guest *gst) -{ - struct Place *plc = &gst->place; - - if (NULL == gst->tmit_handle) - { - struct GNUNET_PSYC_MessageMethod * - pmeth = psyc_transmit_queue_next_method (plc); - if (NULL == pmeth) - return GNUNET_SYSERR; - - gst->tmit_handle = (void *) &gst->tmit_handle; - struct GNUNET_PSYC_SlaveTransmitHandle * - tmit_handle = GNUNET_PSYC_slave_transmit (gst->slave, (const char *) &pmeth[1], - &guest_transmit_notify_mod, - &guest_transmit_notify_data, gst, - pmeth->flags); - if (NULL != gst->tmit_handle) - gst->tmit_handle = tmit_handle; - GNUNET_free (pmeth); - } - else - { - GNUNET_PSYC_slave_transmit_resume (gst->tmit_handle); - } - return GNUNET_OK; -} - - -/** - * Transmit a message to PSYC. - */ -static int -psyc_transmit_message (struct Place *plc) -{ - return - (plc->is_host) - ? psyc_master_transmit_message ((struct Host *) plc) - : psyc_slave_transmit_message ((struct Guest *) plc); -} - - -/** - * Queue message parts for sending to PSYC. - * - * @param plc Place to send to. - * @param client Client the message originates from. - * @param data_size Size of @a data. - * @param data Concatenated message parts. - * @param first_ptype First message part type in @a data. - * @param last_ptype Last message part type in @a data. - */ -static struct MessageTransmitQueue * -psyc_transmit_queue_message (struct Place *plc, - struct GNUNET_SERVICE_Client *client, - size_t data_size, - const void *data, - uint16_t first_ptype, uint16_t last_ptype, - struct MessageTransmitQueue *tmit_msg) -{ - if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == first_ptype) - { - tmit_msg = GNUNET_malloc (sizeof (*tmit_msg)); - GNUNET_CONTAINER_DLL_insert_tail (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg); - } - else if (NULL == tmit_msg) - { - return NULL; - } - - struct FragmentTransmitQueue * - tmit_frag = GNUNET_malloc (sizeof (*tmit_frag) + data_size); - GNUNET_memcpy (&tmit_frag[1], data, data_size); - tmit_frag->next_part = (struct GNUNET_MessageHeader *) &tmit_frag[1]; - tmit_frag->client = client; - tmit_frag->size = data_size; - - GNUNET_CONTAINER_DLL_insert_tail (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag); - tmit_msg->client = client; - return tmit_msg; -} - - -///** -// * Cancel transmission of current message to PSYC. -// * -// * @param plc Place to send to. -// * @param client Client the message originates from. -// */ -//static void -//psyc_transmit_cancel (struct Place *plc, struct GNUNET_SERVICE_Client *client) -//{ -// uint16_t type = GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL; -// -// struct GNUNET_MessageHeader msg; -// msg.size = htons (sizeof (msg)); -// msg.type = htons (type); -// -// psyc_transmit_queue_message (plc, client, sizeof (msg), &msg, type, type, NULL); -// psyc_transmit_message (plc); -// -// /* FIXME: cleanup */ -//} - - -static int -check_client_psyc_message (void *cls, - const struct GNUNET_MessageHeader *msg) -{ - return GNUNET_OK; -} - - -/** - * Handle an incoming message from a client, to be transmitted to the place. - */ -static void -handle_client_psyc_message (void *cls, - const struct GNUNET_MessageHeader *msg) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - struct Place *plc = c->place; - int ret; - - if (NULL == plc) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "received PSYC message for non-existing client %p\n", - client); - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Received message of type %d from client.\n", plc, ntohs (msg->type)); - GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, msg); - - if (GNUNET_YES != plc->is_ready) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "%p Place is not ready yet, disconnecting client.\n", plc); - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - - uint16_t size = ntohs (msg->size); - uint16_t psize = size - sizeof (*msg); - if (psize < sizeof (struct GNUNET_MessageHeader) - || GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < psize) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%p Received message with invalid payload size (%u) from client.\n", - plc, psize); - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - - uint16_t first_ptype = 0; - uint16_t last_ptype = 0; - if (GNUNET_SYSERR == - GNUNET_PSYC_receive_check_parts (psize, (const char *) &msg[1], - &first_ptype, &last_ptype)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%p Received invalid message part from client.\n", plc); - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Received message with first part type %u and last part type %u.\n", - plc, first_ptype, last_ptype); - - c->tmit_msg - = psyc_transmit_queue_message (plc, client, psize, &msg[1], - first_ptype, last_ptype, c->tmit_msg); - if (NULL != c->tmit_msg) - { - if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= last_ptype) - c->tmit_msg = NULL; - ret = psyc_transmit_message (plc); - } - else - { - ret = GNUNET_SYSERR; - } - if (GNUNET_OK != ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%p Received invalid message part from client.\n", plc); - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - GNUNET_SERVICE_client_continue (client); -} - - -/** - * A historic message arrived from PSYC. - */ -static void -psyc_recv_history_message (void *cls, const struct GNUNET_PSYC_MessageHeader *msg) -{ - struct OperationClosure *opcls = cls; - struct Client *c = opcls->client; - struct Place *plc = c->place; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Received historic message #%" PRId64 " (flags: %x)\n", - plc, GNUNET_ntohll (msg->message_id), ntohl (msg->flags)); - - uint16_t size = ntohs (msg->header.size); - - struct GNUNET_OperationResultMessage * - res = GNUNET_malloc (sizeof (*res) + size); - res->header.size = htons (sizeof (*res) + size); - res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT); - res->op_id = opcls->op_id; - res->result_code = GNUNET_htonll (GNUNET_OK); - - GNUNET_memcpy (&res[1], msg, size); - - /** @todo FIXME: send only to requesting client */ - place_send_msg (plc, GNUNET_MQ_msg_copy (&res->header)); - - GNUNET_free (res); -} - - -/** - * Result of message history replay from PSYC. - */ -static void -psyc_recv_history_result (void *cls, int64_t result, - const void *err_msg, uint16_t err_msg_size) -{ - struct OperationClosure *opcls = cls; - struct Client *c = opcls->client; - struct Place *plc = c->place; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p History replay #%" PRIu64 ": " - "PSYCstore returned %" PRId64 " (%.*s)\n", - plc, GNUNET_ntohll (opcls->op_id), result, - err_msg_size, (const char *) err_msg); - - // FIXME: place might have been destroyed - client_send_result (c->client, opcls->op_id, result, err_msg, err_msg_size); -} - - -static int -check_client_history_replay (void *cls, - const struct GNUNET_PSYC_HistoryRequestMessage *req) -{ - return GNUNET_OK; -} - - -/** - * Client requests channel history. - */ -static void -handle_client_history_replay (void *cls, - const struct GNUNET_PSYC_HistoryRequestMessage *req) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - struct Place *plc = c->place; - if (NULL == plc) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - - uint16_t size = ntohs (req->header.size); - const char *method_prefix = (const char *) &req[1]; - - if (size < sizeof (*req) + 1 - || '\0' != method_prefix[size - sizeof (*req) - 1]) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%p History replay #%" PRIu64 ": " - "invalid method prefix. size: %u < %zu?\n", - plc, GNUNET_ntohll (req->op_id), size, sizeof (*req) + 1); - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - - struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls)); - opcls->client = c; - opcls->op_id = req->op_id; - opcls->flags = ntohl (req->flags); - - if (0 == req->message_limit) - GNUNET_PSYC_channel_history_replay (plc->channel, - GNUNET_ntohll (req->start_message_id), - GNUNET_ntohll (req->end_message_id), - method_prefix, opcls->flags, - psyc_recv_history_message, NULL, - psyc_recv_history_result, opcls); - else - GNUNET_PSYC_channel_history_replay_latest (plc->channel, - GNUNET_ntohll (req->message_limit), - method_prefix, opcls->flags, - psyc_recv_history_message, NULL, - psyc_recv_history_result, opcls); - - GNUNET_SERVICE_client_continue (client); -} - - -/** - * A state variable part arrived from PSYC. - */ -void -psyc_recv_state_var (void *cls, - const struct GNUNET_MessageHeader *mod, - const char *name, - const void *value, - uint32_t value_size, - uint32_t full_value_size) -{ - struct GNUNET_OperationResultMessage *result_msg; - struct GNUNET_MQ_Envelope *env; - struct OperationClosure *opcls = cls; - struct Client *c = opcls->client; - struct Place *plc = c->place; - uint16_t size = ntohs (mod->size); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p Received state variable %s from PSYC\n", - plc, name); - env = GNUNET_MQ_msg_extra (result_msg, - size, - GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT); - result_msg->op_id = opcls->op_id; - result_msg->result_code = GNUNET_htonll (GNUNET_OK); - GNUNET_memcpy (&result_msg[1], mod, size); - /** @todo FIXME: send only to requesting client */ - place_send_msg (plc, env); -} - - -/** - * Result of retrieving state variable from PSYC. - */ -static void -psyc_recv_state_result (void *cls, int64_t result, - const void *err_msg, uint16_t err_msg_size) -{ - struct OperationClosure *opcls = cls; - struct Client *c = opcls->client; - struct Place *plc = c->place; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p State get #%" PRIu64 ": " - "PSYCstore returned %" PRId64 " (%.*s)\n", - plc, GNUNET_ntohll (opcls->op_id), result, - err_msg_size, (const char *) err_msg); - - // FIXME: place might have been destroyed - client_send_result (c->client, opcls->op_id, result, err_msg, err_msg_size); -} - - -static int -check_client_state_get (void *cls, - const struct GNUNET_PSYC_StateRequestMessage *req) -{ - return GNUNET_OK; -} - - -/** - * Client requests channel history. - */ -static void -handle_client_state_get (void *cls, - const struct GNUNET_PSYC_StateRequestMessage *req) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - struct Place *plc = c->place; - if (NULL == plc) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - - uint16_t size = ntohs (req->header.size); - const char *name = (const char *) &req[1]; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%p State get #%" PRIu64 ": %s\n", - plc, GNUNET_ntohll (req->op_id), name); - - if (size < sizeof (*req) + 1 - || '\0' != name[size - sizeof (*req) - 1]) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%p State get #%" PRIu64 ": " - "invalid name. size: %u < %zu?\n", - plc, GNUNET_ntohll (req->op_id), size, sizeof (*req) + 1); - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client); - return; - } - - struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls)); - opcls->client = c; - opcls->op_id = req->op_id; - - switch (ntohs (req->header.type)) - { - case GNUNET_MESSAGE_TYPE_PSYC_STATE_GET: - GNUNET_PSYC_channel_state_get (plc->channel, name, - psyc_recv_state_var, - psyc_recv_state_result, opcls); - break; - - case GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX: - GNUNET_PSYC_channel_state_get_prefix (plc->channel, name, - psyc_recv_state_var, - psyc_recv_state_result, opcls); - break; - - default: - GNUNET_assert (0); - } - - GNUNET_SERVICE_client_continue (client); -} - - -#define check_client_state_get_prefix check_client_state_get -#define handle_client_state_get_prefix handle_client_state_get - - -static void -namestore_recv_records_store_result (void *cls, int32_t result, - const char *err_msg) -{ - struct OperationClosure *opcls = cls; - struct Client *c = opcls->client; - - // FIXME: client might have been disconnected - client_send_result (c->client, opcls->op_id, result, err_msg, - (NULL != err_msg) ? strlen (err_msg) : 0); - GNUNET_free (opcls); -} - - -static int -check_client_zone_add_place (void *cls, - const struct ZoneAddPlaceRequest *preq) -{ - return GNUNET_OK; -} - - -/** - * Handle request to add PLACE record to GNS zone. - */ -static void -handle_client_zone_add_place (void *cls, - const struct ZoneAddPlaceRequest *preq) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - - uint16_t remaining = ntohs (preq->header.size) - sizeof (*preq); - const char *p = (const char *) &preq[1]; - const char *name = NULL, *password = NULL; - uint16_t offset = GNUNET_STRINGS_buffer_tokenize (p, remaining, 2, - &name, &password); - remaining -= offset; - p += offset; - const struct GNUNET_PeerIdentity * - relays = (const struct GNUNET_PeerIdentity *) p; - uint16_t relay_size = ntohl (preq->relay_count) * sizeof (*relays); - - if (0 == offset || remaining != relay_size) - { - GNUNET_break (0); - client_send_result (client, preq->op_id, GNUNET_SYSERR, NULL, 0); - GNUNET_SERVICE_client_drop (client); - return; - } - - struct GNUNET_GNSRECORD_Data rd = { }; - rd.record_type = GNUNET_GNSRECORD_TYPE_PLACE; - rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; - rd.expiration_time = GNUNET_ntohll (preq->expiration_time); - - struct GNUNET_GNSRECORD_PlaceData * - rec = GNUNET_malloc (sizeof (*rec) + relay_size); - rec->place_pub_key = preq->place_pub_key; - rec->origin = this_peer; - rec->relay_count = preq->relay_count; - GNUNET_memcpy (&rec[1], relays, relay_size); - - rd.data = rec; - rd.data_size = sizeof (*rec) + relay_size; - - struct GNUNET_HashCode ego_pub_hash; - GNUNET_CRYPTO_hash (&preq->ego_pub_key, sizeof (preq->ego_pub_key), &ego_pub_hash); - struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash); - if (NULL == ego) - { - client_send_result (client, preq->op_id, GNUNET_SYSERR, NULL, 0); - } - else - { - struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls)); - opcls->client = c; - opcls->op_id = preq->op_id; - GNUNET_NAMESTORE_records_store (namestore, &ego->key, - name, 1, &rd, - namestore_recv_records_store_result, opcls); - /** @todo refresh stored records later */ - } - GNUNET_SERVICE_client_continue (client); -} - - -static int -check_client_zone_add_nym (void *cls, - const struct ZoneAddNymRequest *nreq) -{ - return GNUNET_OK; -} - - -/** - * Handle request to add PLACE record to GNS zone. - */ -static void -handle_client_zone_add_nym (void *cls, - const struct ZoneAddNymRequest *nreq) -{ - struct Client *c = cls; - struct GNUNET_SERVICE_Client *client = c->client; - - uint16_t name_size = ntohs (nreq->header.size) - sizeof (*nreq); - const char *name = NULL; - uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &nreq[1], - name_size, 1, &name); - if (0 == offset || offset != name_size) - { - GNUNET_break (0); - client_send_result (client, nreq->op_id, GNUNET_SYSERR, NULL, 0); - GNUNET_SERVICE_client_continue (client); - return; - } - - struct GNUNET_GNSRECORD_Data rd = { }; - rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY; - rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; - rd.expiration_time = GNUNET_ntohll (nreq->expiration_time); - rd.data = &nreq->nym_pub_key; - rd.data_size = sizeof (nreq->nym_pub_key); - - struct GNUNET_HashCode ego_pub_hash; - GNUNET_CRYPTO_hash (&nreq->ego_pub_key, sizeof (nreq->ego_pub_key), &ego_pub_hash); - struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash); - if (NULL == ego) - { - client_send_result (client, nreq->op_id, GNUNET_SYSERR, NULL, 0); - } - else - { - struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls)); - opcls->client = c; - opcls->op_id = nreq->op_id; - GNUNET_NAMESTORE_records_store (namestore, &ego->key, - name, 1, &rd, - namestore_recv_records_store_result, opcls); - /** @todo refresh stored records later */ - } - GNUNET_SERVICE_client_continue (client); -} - - -const char * -path_basename (const char *path) -{ - const char *basename = strrchr (path, DIR_SEPARATOR); - if (NULL != basename) - basename++; - - if (NULL == basename || '\0' == *basename) - return NULL; - - return basename; -} - - -struct PlaceLoadClosure -{ - const char *app_id; - const char *ego_pub_str; -}; - - -/** Load a place file */ -int -file_place_load (void *cls, const char *place_filename) -{ - struct PlaceLoadClosure *plcls = cls; - - const char *place_pub_str = path_basename (place_filename); - if (NULL == place_pub_str) - { - GNUNET_break (0); - return GNUNET_OK; - } - - char *filename = NULL; - GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s", - dir_social, DIR_SEPARATOR, - "places", DIR_SEPARATOR, - plcls->ego_pub_str, DIR_SEPARATOR, - place_pub_str); - - uint64_t file_size = 0; - if (GNUNET_OK != - GNUNET_DISK_file_size (filename, &file_size, GNUNET_YES, GNUNET_YES) - || file_size < sizeof (struct PlaceEnterRequest)) - { - GNUNET_free (filename); - return GNUNET_OK; - } - - struct PlaceEnterRequest *ereq = GNUNET_malloc (file_size); - ssize_t read_size = GNUNET_DISK_fn_read (filename, ereq, file_size); - GNUNET_free (filename); - if (read_size < 0 || read_size < sizeof (*ereq)) - { - GNUNET_free (ereq); - return GNUNET_OK; - } - - uint16_t ereq_size = ntohs (ereq->header.size); - if (read_size != ereq_size) - { - GNUNET_free (ereq); - return GNUNET_OK; - } - - switch (ntohs (ereq->header.type)) - { - case GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER: - if (ereq_size < sizeof (struct HostEnterRequest)) - { - GNUNET_free (ereq); - return GNUNET_OK; - } - struct HostEnterRequest *hreq = (struct HostEnterRequest *) ereq; - host_enter (hreq, NULL); - break; - - case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER: - if (ereq_size < sizeof (struct GuestEnterRequest)) - { - GNUNET_free (ereq); - return GNUNET_OK; - } - struct GuestEnterRequest *greq = (struct GuestEnterRequest *) ereq; - guest_enter (greq, NULL); - break; - - default: - GNUNET_free (ereq); - return GNUNET_OK; - } - - if (GNUNET_SYSERR == app_place_add (plcls->app_id, ereq)) - { - GNUNET_assert (0); - } - GNUNET_free (ereq); - return GNUNET_OK; -} - - -/** - * Read @e place_pub_str entries in @a dir_ego - * - * @param dir_ego - * Data directory of an application ego. - * $GNUNET_DATA_HOME/social/apps/$app_id/$ego_pub_str/ - */ -int -scan_app_ego_dir (void *cls, const char *dir_ego) -{ - struct PlaceLoadClosure *plcls = cls; - plcls->ego_pub_str = path_basename (dir_ego); - - if (NULL != plcls->ego_pub_str) - GNUNET_DISK_directory_scan (dir_ego, file_place_load, plcls); - - return GNUNET_OK; -} - -/** - * Read @e ego_pub_str entries in @a dir_app - * - * @param dir_app - * Data directory of an application. - * $GNUNET_DATA_HOME/social/apps/$app_id/ - */ -int -scan_app_dir (void *cls, const char *dir_app) -{ - if (GNUNET_YES != GNUNET_DISK_directory_test (dir_app, GNUNET_YES)) - return GNUNET_OK; - - struct PlaceLoadClosure plcls; - plcls.app_id = path_basename (dir_app); - - if (NULL != plcls.app_id) - GNUNET_DISK_directory_scan (dir_app, scan_app_ego_dir, &plcls); - - return GNUNET_OK; -} - - -static void -identity_recv_ego (void *cls, struct GNUNET_IDENTITY_Ego *id_ego, - void **ctx, const char *name) -{ - if (NULL == id_ego) // end of initial list of egos - return; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "social service received ego %s\n", - name); - - struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; - GNUNET_IDENTITY_ego_get_public_key (id_ego, &ego_pub_key); - - struct GNUNET_HashCode ego_pub_hash; - GNUNET_CRYPTO_hash (&ego_pub_key, sizeof (ego_pub_key), &ego_pub_hash); - - struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash); - if (NULL == ego && NULL == name) - { - // an ego that is none of our business has been deleted - return; - } - if (NULL != ego) - { - // one of our egos has been changed - GNUNET_free (ego->name); - if (NULL == name) - { - // one of our egos has been deleted - GNUNET_CONTAINER_multihashmap_remove (egos, &ego_pub_hash, ego); - GNUNET_free (ego); - return; - } - } - else - { - ego = GNUNET_malloc (sizeof (*ego)); - } - ego->key = *(GNUNET_IDENTITY_ego_get_private_key (id_ego)); - size_t name_size = strlen (name) + 1; - ego->name = GNUNET_malloc (name_size); - GNUNET_memcpy (ego->name, name, name_size); - - GNUNET_CONTAINER_multihashmap_put (egos, &ego_pub_hash, ego, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); - - // FIXME: notify clients about changed ego -} - - -/** - * Initialize the PSYC service. - * - * @param cls Closure. - * @param server The initialized server. - * @param c Configuration to use. - */ -static void -run (void *cls, - const struct GNUNET_CONFIGURATION_Handle *c, - struct GNUNET_SERVICE_Handle *svc) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "starting social service\n"); - - cfg = c; - service = svc; - GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer); - - hosts = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); - guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); - place_guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - - egos = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - apps = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - places = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO); - apps_places = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO); - //places_apps = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO); - - id = GNUNET_IDENTITY_connect (cfg, &identity_recv_ego, NULL); - gns = GNUNET_GNS_connect (cfg); - namestore = GNUNET_NAMESTORE_connect (cfg); - stats = GNUNET_STATISTICS_create ("social", cfg); - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (cfg, "social", "DATA_HOME", - &dir_social)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "social", "DATA_HOME"); - GNUNET_break (0); - return; - } - GNUNET_asprintf (&dir_places, "%s%c%s", - dir_social, DIR_SEPARATOR, "places"); - GNUNET_asprintf (&dir_apps, "%s%c%s", - dir_social, DIR_SEPARATOR, "apps"); - - GNUNET_DISK_directory_scan (dir_apps, scan_app_dir, NULL); - - GNUNET_SCHEDULER_add_shutdown (shutdown_task, NULL); -} - - -/** - * Define "main" method using service macro. - */ -GNUNET_SERVICE_MAIN -("social", - GNUNET_SERVICE_OPTION_NONE, - run, - client_notify_connect, - client_notify_disconnect, - NULL, - GNUNET_MQ_hd_var_size (client_host_enter, - GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER, - struct HostEnterRequest, - NULL), - GNUNET_MQ_hd_var_size (client_guest_enter, - GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER, - struct GuestEnterRequest, - NULL), - GNUNET_MQ_hd_var_size (client_guest_enter_by_name, - GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME, - struct GuestEnterByNameRequest, - NULL), - GNUNET_MQ_hd_var_size (client_join_decision, - GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION, - struct GNUNET_PSYC_JoinDecisionMessage, - NULL), - GNUNET_MQ_hd_var_size (client_psyc_message, - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, - struct GNUNET_MessageHeader, - NULL), - GNUNET_MQ_hd_var_size (client_history_replay, - GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY, - struct GNUNET_PSYC_HistoryRequestMessage, - NULL), - GNUNET_MQ_hd_var_size (client_state_get, - GNUNET_MESSAGE_TYPE_PSYC_STATE_GET, - struct GNUNET_PSYC_StateRequestMessage, - NULL), - GNUNET_MQ_hd_var_size (client_state_get_prefix, - GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX, - struct GNUNET_PSYC_StateRequestMessage, - NULL), - GNUNET_MQ_hd_var_size (client_zone_add_place, - GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_PLACE, - struct ZoneAddPlaceRequest, - NULL), - GNUNET_MQ_hd_var_size (client_zone_add_nym, - GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_NYM, - struct ZoneAddNymRequest, - NULL), - GNUNET_MQ_hd_var_size (client_app_connect, - GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT, - struct AppConnectRequest, - NULL), - GNUNET_MQ_hd_fixed_size (client_app_detach, - GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH, - struct AppDetachRequest, - NULL), - GNUNET_MQ_hd_fixed_size (client_place_leave, - GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE, - struct GNUNET_MessageHeader, - NULL), - GNUNET_MQ_hd_var_size (client_msg_proc_set, - GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_SET, - struct MsgProcRequest, - NULL), - GNUNET_MQ_hd_fixed_size (client_msg_proc_clear, - GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_CLEAR, - struct GNUNET_MessageHeader, - NULL)); - -/* end of gnunet-service-social.c */ diff --git a/src/social/gnunet-social.c b/src/social/gnunet-social.c deleted file mode 100644 index 14701bfda..000000000 --- a/src/social/gnunet-social.c +++ /dev/null @@ -1,1411 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2016 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later -*/ - -/** - * CLI tool to interact with the social service. - * - * @author Gabor X Toth - */ - -#include - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_social_service.h" - -#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) - -#define DATA2ARG(data) data, sizeof (data) - -/* operations corresponding to API calls */ - -/** --status */ -static int op_status; - -/** --host-enter */ -static int op_host_enter; - -/** --host-reconnect */ -static int op_host_reconnect; - -/** --host-leave */ -static int op_host_leave; - -/** --host-announce */ -static int op_host_announce; - -/** --host-assign */ -static int op_host_assign; - -/** --guest-enter */ -static int op_guest_enter; - -/** --guest-reconnect */ -static int op_guest_reconnect; - -/** --guest-leave */ -static int op_guest_leave; - -/** --guest-talk */ -static int op_guest_talk; - -/** --replay */ -static int op_replay; - -/** --replay-latest */ -static int op_replay_latest; - -/** --look-at */ -static int op_look_at; - -/** --look-for */ -static int op_look_for; - - -/* options */ - -/** --app */ -static char *opt_app = "cli"; - -/** --place */ -static char *opt_place; - -/** --ego */ -static char *opt_ego; - -/** --gns */ -static char *opt_gns; - -/** --peer */ -static char *opt_peer; - -/** --follow */ -static int opt_follow; - -/** --welcome */ -static int opt_welcome; - -/** --deny */ -static int opt_deny; - -/** --method */ -static char *opt_method; - -/** --data */ -// FIXME: should come from STDIN -static char *opt_data; - -/** --name */ -static char *opt_name; - -/** --start */ -static unsigned long long opt_start; - -/** --until */ -static unsigned long long opt_until; - -/** --limit */ -static unsigned long long opt_limit; - - -/* global vars */ - -/** exit code */ -static int ret = 1; - -/** are we waiting for service to close our connection */ -static char is_disconnecting = 0; - -/** Task handle for timeout termination. */ -struct GNUNET_SCHEDULER_Task *timeout_task; - -const struct GNUNET_CONFIGURATION_Handle *cfg; - -struct GNUNET_PeerIdentity peer, this_peer; - -struct GNUNET_SOCIAL_App *app; - -/** public key of connected place */ -struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; - -struct GNUNET_PSYC_Slicer *slicer; - -struct GNUNET_SOCIAL_Ego *ego; -struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; - -struct GNUNET_SOCIAL_Host *hst; -struct GNUNET_SOCIAL_Guest *gst; -struct GNUNET_SOCIAL_Place *plc; - -const char *method_received; - - -/* DISCONNECT */ - - -/** - * Callback called after the host or guest place disconnected. - */ -static void -disconnected (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnected()\n"); - GNUNET_SCHEDULER_shutdown (); -} - - -/** - * Callback called after the application disconnected. - */ -static void -app_disconnected (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "app_disconnected()\n"); - if (hst || gst) - { - if (hst) - { - GNUNET_SOCIAL_host_disconnect (hst, disconnected, NULL); - } - if (gst) - { - GNUNET_SOCIAL_guest_disconnect (gst, disconnected, NULL); - } - } - else - { - GNUNET_SCHEDULER_shutdown (); - } -} - - -/** - * Disconnect from connected GNUnet services. - */ -static void -disconnect () -{ - // handle that we get called several times from several places, but should we? - if (!is_disconnecting++) { - GNUNET_SOCIAL_app_disconnect (app, app_disconnected, NULL); - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnect() called for the #%d time\n", is_disconnecting); -} - - -static void -scheduler_shutdown (void *cls) -{ - disconnect (); -} - - -/** - * Callback called when the program failed to finish the requested operation in time. - */ -static void -timeout (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "timeout()\n"); - disconnect (); -} - -static void -schedule_success (void *cls) -{ - ret = 0; - disconnect (); -} - - -static void -schedule_fail (void *cls) -{ - disconnect (); -} - - -/** - * Schedule exit with success result. - */ -static void -exit_success () -{ - if (timeout_task != NULL) - { - GNUNET_SCHEDULER_cancel (timeout_task); - timeout_task = NULL; - } - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, schedule_success, NULL); -} - - -/** - * Schedule exit with failure result. - */ -static void -exit_fail () -{ - if (timeout_task != NULL) - { - GNUNET_SCHEDULER_cancel (timeout_task); - timeout_task = NULL; - } - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, schedule_fail, NULL); -} - - -/* LEAVE */ - - -/** - * Callback notifying about the host has left and stopped hosting the place. - * - * This also indicates the end of the connection to the service. - */ -static void -host_left (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "The host has left the place.\n"); - exit_success (); -} - - -/** - * Leave a place permanently and stop hosting a place. - */ -static void -host_leave () -{ - GNUNET_SOCIAL_host_leave (hst, NULL, host_left, NULL); - hst = NULL; - plc = NULL; -} - - -/** - * Callback notifying about the guest has left the place. - * - * This also indicates the end of the connection to the service. - */ -static void -guest_left (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Guest has left the place.\n"); -} - - -/** - * Leave a place permanently as guest. - */ -static void -guest_leave () -{ - struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); - // FIXME: wrong use of vars - GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET, - "_message", DATA2ARG ("Leaving.")); - GNUNET_SOCIAL_guest_leave (gst, env, guest_left, NULL); - GNUNET_PSYC_env_destroy (env); - gst = NULL; - plc = NULL; -} - - -/* ANNOUNCE / ASSIGN / TALK */ - - -struct TransmitClosure -{ - const char *data; - size_t size; -} tmit; - - -/** - * Callback notifying about available buffer space to write message data - * when transmitting messages using host_announce() or guest_talk() - */ -static int -notify_data (void *cls, uint16_t *data_size, void *data) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Transmit notify data: %u bytes available\n", - *data_size); - - struct TransmitClosure *tmit = cls; - uint16_t size = tmit->size < *data_size ? tmit->size : *data_size; - *data_size = size; - GNUNET_memcpy (data, tmit->data, size); - - tmit->size -= size; - tmit->data += size; - - if (0 == tmit->size) - { - if ((op_host_announce || op_host_assign || op_guest_talk) && !opt_follow) - { - exit_success (); - } - return GNUNET_YES; - } - else - { - return GNUNET_NO; - } -} - - -/** - * Host announcement - send a message to the place. - */ -static void -host_announce (const char *method, const char *data, size_t data_size) -{ - struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); - GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET, - "_foo", DATA2ARG ("bar baz")); - - tmit = (struct TransmitClosure) {}; - tmit.data = data; - tmit.size = data_size; - - GNUNET_SOCIAL_host_announce (hst, method, env, - notify_data, &tmit, - GNUNET_SOCIAL_ANNOUNCE_NONE); - GNUNET_PSYC_env_destroy (env); -} - - -/** - * Assign a state var of @a name to the value of @a data. - */ -static void -host_assign (const char *name, const char *data, size_t data_size) -{ - struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); - GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN, - name, data, data_size); - - tmit = (struct TransmitClosure) {}; - GNUNET_SOCIAL_host_announce (hst, "_assign", env, - notify_data, &tmit, - GNUNET_SOCIAL_ANNOUNCE_NONE); - GNUNET_PSYC_env_destroy (env); -} - - -/** - * Guest talk request to host. - */ -static void -guest_talk (const char *method, - const char *data, size_t data_size) -{ - struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); - GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET, - "_foo", DATA2ARG ("bar baz")); - - tmit = (struct TransmitClosure) {}; - tmit.data = data; - tmit.size = data_size; - - GNUNET_SOCIAL_guest_talk (gst, method, env, - notify_data, &tmit, - GNUNET_SOCIAL_TALK_NONE); - GNUNET_PSYC_env_destroy (env); -} - - -/* HISTORY REPLAY */ - - -/** - * Callback notifying about the end of history replay results. - */ -static void -recv_history_replay_result (void *cls, int64_t result, - const void *data, uint16_t data_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received history replay result: %" PRId64 "\n" - "%.*s\n", - result, data_size, (const char *) data); - - if (op_replay || op_replay_latest) - { - exit_success (); - } -} - - -/** - * Replay history between a given @a start and @a end message IDs, - * optionally filtered by a method @a prefix. - */ -static void -history_replay (uint64_t start, uint64_t end, const char *prefix) -{ - GNUNET_SOCIAL_place_history_replay (plc, start, end, prefix, - GNUNET_PSYC_HISTORY_REPLAY_LOCAL, - slicer, - recv_history_replay_result, - NULL); -} - - -/** - * Replay latest @a limit messages. - */ -static void -history_replay_latest (uint64_t limit, const char *prefix) -{ - GNUNET_SOCIAL_place_history_replay_latest (plc, limit, prefix, - GNUNET_PSYC_HISTORY_REPLAY_LOCAL, - slicer, - recv_history_replay_result, - NULL); -} - - -/* LOOK AT/FOR */ - - -/** - * Callback notifying about the end of state var results. - */ -static void -look_result (void *cls, int64_t result_code, - const void *data, uint16_t data_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received look result: %" PRId64 "\n", result_code); - - if (op_look_at || op_look_for) - { - exit_success (); - } -} - - -/** - * Callback notifying about a state var result. - */ -static void -look_var (void *cls, - const struct GNUNET_MessageHeader *mod, - const char *name, - const void *value, - uint32_t value_size, - uint32_t full_value_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Received var: %s\n%.*s\n", - name, value_size, (const char *) value); -} - - -/** - * Look for a state var using exact match of the name. - */ -static void -look_at (const char *full_name) -{ - GNUNET_SOCIAL_place_look_at (plc, full_name, look_var, look_result, NULL); -} - - -/** - * Look for state vars by name prefix. - */ -static void -look_for (const char *name_prefix) -{ - GNUNET_SOCIAL_place_look_for (plc, name_prefix, look_var, look_result, NULL); -} - - -/* SLICER */ - - -/** - * Callback notifying about the start of a new incoming message. - */ -static void -slicer_recv_method (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_PSYC_MessageMethod *meth, - uint64_t message_id, - const char *method_name) -{ - method_received = method_name; - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Received method for message ID %" PRIu64 ":\n" - "%s (flags: %x)\n", - message_id, method_name, ntohl (meth->flags)); - /* routing header is missing, so we just print double newline */ - printf("\n"); - /* we output . instead of | to indicate that this is not proper PSYC syntax */ - /* FIXME: use libpsyc here */ -} - - -/** - * Callback notifying about an incoming modifier. - */ -static void -slicer_recv_modifier (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg, - uint64_t message_id, - enum GNUNET_PSYC_Operator oper, - const char *name, - const void *value, - uint16_t value_size, - uint16_t full_value_size) -{ -#if 0 - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Received modifier for message ID %" PRIu64 ":\n" - "%c%s: %.*s (size: %u)\n", - message_id, oper, name, value_size, (const char *) value, value_size); -#else - /* obviously not binary safe */ - printf("%c%s\t%.*s\n", - oper, name, value_size, (const char *) value); -#endif -} - - -/** - * Callback notifying about an incoming data fragment. - */ -static void -slicer_recv_data (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg, - uint64_t message_id, - const void *data, - uint16_t data_size) -{ -#if 0 - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Received data for message ID %" PRIu64 ":\n" - "%.*s\n", - message_id, data_size, (const char *) data); -#else - /* obviously not binary safe */ - printf("%s\n%.*s\n", - method_received, data_size, (const char *) data); -#endif -} - - -/** - * Callback notifying about the end of a message. - */ -static void -slicer_recv_eom (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg, - uint64_t message_id, - uint8_t is_cancelled) -{ - printf(".\n"); - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Received end of message ID %" PRIu64 - ", cancelled: %u\n", - message_id, is_cancelled); -} - - -/** - * Create a slicer for receiving message parts. - */ -static struct GNUNET_PSYC_Slicer * -slicer_create () -{ - slicer = GNUNET_PSYC_slicer_create (); - - /* register slicer to receive incoming messages with any method name */ - GNUNET_PSYC_slicer_method_add (slicer, "", NULL, - slicer_recv_method, slicer_recv_modifier, - slicer_recv_data, slicer_recv_eom, NULL); - return slicer; -} - - -/* GUEST ENTER */ - - -/** - * Callback called when the guest receives an entry decision from the host. - * - * It is called once after using guest_enter() or guest_enter_by_name(), - * in case of a reconnection only the local enter callback is called. - */ -static void -guest_recv_entry_decision (void *cls, - int is_admitted, - const struct GNUNET_PSYC_Message *entry_msg) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Guest received entry decision %d\n", - is_admitted); - - if (NULL != entry_msg) - { - struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); - const char *method_name = NULL; - const void *data = NULL; - uint16_t data_size = 0; - struct GNUNET_PSYC_MessageHeader * - pmsg = GNUNET_PSYC_message_header_create_from_psyc (entry_msg); - GNUNET_PSYC_message_parse (pmsg, &method_name, env, &data, &data_size); - GNUNET_free (pmsg); - - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "%s\n%.*s\n", - method_name, data_size, (const char *) data); - } - - if (op_guest_enter && !opt_follow) - { - exit_success (); - } -} - - -/** - * Callback called after a guest connection is established to the local service. - */ -static void -guest_recv_local_enter (void *cls, int result, - const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key, - uint64_t max_message_id) -{ - char *pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (pub_key); - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Guest entered local place: %s, max_message_id: %" PRIu64 "\n", - pub_str, max_message_id); - GNUNET_free (pub_str); - GNUNET_assert (0 <= result); - - if (op_guest_enter && !opt_follow) - { - exit_success (); - } -} - - -/** - * Create entry request message. - */ -static struct GNUNET_PSYC_Message * -guest_enter_msg_create () -{ - const char *method_name = "_request_enter"; - struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); - GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET, - "_foo", DATA2ARG ("bar")); - void *data = "let me in"; - uint16_t data_size = strlen (data) + 1; - - return GNUNET_PSYC_message_create (method_name, env, data, data_size); -} - - -/** - * Enter a place as guest, using its public key and peer ID. - */ -static void -guest_enter (const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key, - const struct GNUNET_PeerIdentity *peer) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Entering to place as guest.\n"); - - if (NULL == ego) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "--ego missing or invalid\n"); - exit_fail (); - return; - } - - struct GNUNET_PSYC_Message *join_msg = guest_enter_msg_create (); - gst = GNUNET_SOCIAL_guest_enter (app, ego, pub_key, - GNUNET_PSYC_SLAVE_JOIN_NONE, - peer, 0, NULL, join_msg, slicer_create (), - guest_recv_local_enter, - guest_recv_entry_decision, NULL); - GNUNET_free (join_msg); - plc = GNUNET_SOCIAL_guest_get_place (gst); -} - - -/** - * Enter a place as guest using its GNS address. - */ -static void -guest_enter_by_name (const char *gns_name) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Entering to place by name as guest.\n"); - - struct GNUNET_PSYC_Message *join_msg = guest_enter_msg_create (); - gst = GNUNET_SOCIAL_guest_enter_by_name (app, ego, gns_name, NULL, - join_msg, slicer, - guest_recv_local_enter, - guest_recv_entry_decision, NULL); - GNUNET_free (join_msg); - plc = GNUNET_SOCIAL_guest_get_place (gst); -} - - -/* HOST ENTER */ - - -/** - * Callback called when a @a nym wants to enter the place. - * - * The request needs to be replied with an entry decision. - */ -static void -host_answer_door (void *cls, - struct GNUNET_SOCIAL_Nym *nym, - const char *method_name, - struct GNUNET_PSYC_Environment *env, - const void *data, - size_t data_size) -{ - const struct GNUNET_CRYPTO_EcdsaPublicKey * - nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym); - char * - nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key); - - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Entry request: %s\n", nym_str); - GNUNET_free (nym_str); - - if (opt_welcome) - { - struct GNUNET_PSYC_Message * - resp = GNUNET_PSYC_message_create ("_notice_place_admit", env, - DATA2ARG ("Welcome, nym!")); - GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_YES, resp); - GNUNET_free (resp); - } - else if (opt_deny) - { - struct GNUNET_PSYC_Message * - resp = GNUNET_PSYC_message_create ("_notice_place_refuse", NULL, - DATA2ARG ("Go away!")); - GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_NO, resp); - GNUNET_free (resp); - } - - -} - - -/** - * Callback called when a @a nym has left the place. - */ -static void -host_farewell (void *cls, - const struct GNUNET_SOCIAL_Nym *nym, - struct GNUNET_PSYC_Environment *env) -{ - const struct GNUNET_CRYPTO_EcdsaPublicKey * - nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym); - char * - nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key); - - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Farewell: %s\n", nym_str); - GNUNET_free (nym_str); -} - - -/** - * Callback called after the host entered the place. - */ -static void -host_entered (void *cls, int result, - const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key, - uint64_t max_message_id) -{ - place_pub_key = *pub_key; - char *pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (pub_key); - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Host entered: %s, max_message_id: %" PRIu64 "\n", - pub_str, max_message_id); - GNUNET_free (pub_str); - - if (op_host_enter && !opt_follow) - { - exit_success (); - } -} - - -/** - * Enter and start hosting a place. - */ -static void -host_enter () -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "host_enter()\n"); - - if (NULL == ego) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "--ego missing or invalid\n"); - exit_fail (); - return; - } - - hst = GNUNET_SOCIAL_host_enter (app, ego, - GNUNET_PSYC_CHANNEL_PRIVATE, - slicer_create (), host_entered, - host_answer_door, host_farewell, NULL); - plc = GNUNET_SOCIAL_host_get_place (hst); -} - - -/* PLACE RECONNECT */ - - -/** - * Perform operations common to both host & guest places. - */ -static void -place_reconnected () -{ - static int first_run = GNUNET_YES; - if (GNUNET_NO == first_run) - return; - first_run = GNUNET_NO; - - if (op_replay) { - history_replay (opt_start, opt_until, opt_method); - } - else if (op_replay_latest) { - history_replay_latest (opt_limit, opt_method); - } - else if (op_look_at) { - look_at (opt_name); - } - else if (op_look_for) { - look_for (opt_name); - } -} - - -/** - * Callback called after reconnecting to a host place. - */ -static void -host_reconnected (void *cls, int result, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, - uint64_t max_message_id) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Host reconnected.\n"); - - if (op_host_leave) { - host_leave (); - } - else if (op_host_announce) { - host_announce (opt_method, opt_data, strlen (opt_data)); - } - else if (op_host_assign) { - host_assign (opt_name, opt_data, strlen (opt_data) + 1); - } - else { - place_reconnected (); - } -} - - -/** - * Callback called after reconnecting to a guest place. - */ -static void -guest_reconnected (void *cls, int result, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, - uint64_t max_message_id) -{ - char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (place_pub_key); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Guest reconnected to place %s.\n", place_pub_str); - GNUNET_free (place_pub_str); - - if (op_guest_leave) { - guest_leave (); - } - else if (op_guest_talk) { - guest_talk (opt_method, opt_data, strlen (opt_data)); - } - else { - place_reconnected (); - } -} - - -/* APP */ - - -/** - * Callback called after the ego and place callbacks. - */ -static void -app_connected (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "App connected: %p\n", cls); - - if (op_status) - { - exit_success (); - } - else if (op_host_enter) - { - host_enter (); - } - else if (op_guest_enter) - { - if (opt_gns) - { - guest_enter_by_name (opt_gns); - } - else - { - if (opt_peer) - { - if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (opt_peer, - strlen (opt_peer), - &peer.public_key)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "--peer invalid"); - exit_fail (); - return; - } - } - else - { - peer = this_peer; - } - guest_enter (&place_pub_key, &peer); - } - } - printf(".\n"); -} - - -/** - * Callback notifying about a host place available for reconnection. - */ -static void -app_recv_host (void *cls, - struct GNUNET_SOCIAL_HostConnection *hconn, - struct GNUNET_SOCIAL_Ego *ego, - const struct GNUNET_CRYPTO_EddsaPublicKey *host_pub_key, - enum GNUNET_SOCIAL_AppPlaceState place_state) -{ - char *host_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (host_pub_key); - printf ("Host\t%s\n", host_pub_str); - GNUNET_free (host_pub_str); - - if ((op_host_reconnect || op_host_leave || op_host_announce || op_host_assign - || op_replay || op_replay_latest - || op_look_at || op_look_for) - && 0 == memcmp (&place_pub_key, host_pub_key, sizeof (*host_pub_key))) - { - hst = GNUNET_SOCIAL_host_enter_reconnect (hconn, slicer_create (), host_reconnected, - host_answer_door, host_farewell, NULL); - plc = GNUNET_SOCIAL_host_get_place (hst); - } -} - - -/** - * Callback notifying about a guest place available for reconnection. - */ -static void -app_recv_guest (void *cls, - struct GNUNET_SOCIAL_GuestConnection *gconn, - struct GNUNET_SOCIAL_Ego *ego, - const struct GNUNET_CRYPTO_EddsaPublicKey *guest_pub_key, - enum GNUNET_SOCIAL_AppPlaceState place_state) -{ - char *guest_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (guest_pub_key); - printf ("Guest\t%s\n", guest_pub_str); - GNUNET_free (guest_pub_str); - - if ((op_guest_reconnect || op_guest_leave || op_guest_talk - || op_replay || op_replay_latest - || op_look_at || op_look_for) - && 0 == memcmp (&place_pub_key, guest_pub_key, sizeof (*guest_pub_key))) - { - gst = GNUNET_SOCIAL_guest_enter_reconnect (gconn, GNUNET_PSYC_SLAVE_JOIN_NONE, - slicer_create (), guest_reconnected, NULL); - plc = GNUNET_SOCIAL_guest_get_place (gst); - } -} - - -/** - * Callback notifying about an available ego. - */ -static void -app_recv_ego (void *cls, - struct GNUNET_SOCIAL_Ego *e, - const struct GNUNET_CRYPTO_EcdsaPublicKey *pub_key, - const char *name) -{ - char *s = GNUNET_CRYPTO_ecdsa_public_key_to_string (pub_key); - printf ("Ego\t%s\t%s\n", s, name); - GNUNET_free (s); - - if (0 == memcmp (&ego_pub_key, pub_key, sizeof (*pub_key)) - || (NULL != opt_ego && 0 == strcmp (opt_ego, name))) - { - ego = e; - } - -} - - - -/** - * Establish application connection to receive available egos and places. - */ -static void -app_connect (void *cls) -{ - app = GNUNET_SOCIAL_app_connect (cfg, opt_app, - app_recv_ego, - app_recv_host, - app_recv_guest, - app_connected, - NULL); -} - - -/** - * Main function run by the scheduler. - * - * @param cls closure - * @param args remaining command-line arguments - * @param cfgfile name of the configuration file used (for saving, can be NULL!) - * @param c configuration - */ -static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *c) -{ - cfg = c; - GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer); - - if (!opt_method) - opt_method = "message"; - if (!opt_data) - opt_data = ""; - if (!opt_name) - opt_name = ""; - - if (! (op_status - || op_host_enter || op_host_reconnect || op_host_leave - || op_host_announce || op_host_assign - || op_guest_enter || op_guest_reconnect - || op_guest_leave || op_guest_talk - || op_replay || op_replay_latest - || op_look_at || op_look_for)) - { - op_status = 1; - fputs("Caution: This tool does not produce correct binary safe PSYC syntax.\n\n", stderr); - } - - GNUNET_SCHEDULER_add_shutdown (scheduler_shutdown, NULL); - if (!opt_follow) - { - timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, timeout, NULL); - } - - if ((op_host_reconnect || op_host_leave || op_host_announce || op_host_assign - || op_guest_reconnect || (op_guest_enter && !opt_gns) - || op_guest_leave || op_guest_talk - || op_replay || op_replay_latest - || op_look_at || op_look_for) - && (!opt_place - || GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (opt_place, - strlen (opt_place), - &place_pub_key))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("--place missing or invalid.\n")); - /* FIXME: why does it segfault here? */ - exit_fail (); - return; - } - - if (opt_ego) - { - if (GNUNET_OK != - GNUNET_CRYPTO_ecdsa_public_key_from_string (opt_ego, - strlen (opt_ego), - &ego_pub_key)) - { - FPRINTF (stderr, - _("Public key `%s' malformed\n"), - opt_ego); - exit_fail (); - return; - } - } - - GNUNET_SCHEDULER_add_now (app_connect, NULL); -} - - -/** - * The main function to obtain peer information. - * - * @param argc number of arguments from the command line - * @param argv command line arguments - * @return 0 ok, 1 on error - */ -int -main (int argc, char *const *argv) -{ - int res; - struct GNUNET_GETOPT_CommandLineOption options[] = { - /* - * gnunet program options in addition to the ones below: - * - * -c, --config=FILENAME - * -l, --logfile=LOGFILE - * -L, --log=LOGLEVEL - * -h, --help - * -v, --version - */ - - /* operations */ - - GNUNET_GETOPT_option_flag ('A', - "host-assign", - gettext_noop ("assign --name in state to --data"), - &op_host_assign), - - GNUNET_GETOPT_option_flag ('B', - "guest-leave", - gettext_noop ("say good-bye and leave somebody else's place"), - &op_guest_leave), - - GNUNET_GETOPT_option_flag ('C', - "host-enter", - gettext_noop ("create a place"), - &op_host_enter), - - GNUNET_GETOPT_option_flag ('D', - "host-leave", - gettext_noop ("destroy a place we were hosting"), - &op_host_leave), - - GNUNET_GETOPT_option_flag ('E', - "guest-enter", - gettext_noop ("enter somebody else's place"), - &op_guest_enter), - - - GNUNET_GETOPT_option_flag ('F', - "look-for", - gettext_noop ("find state matching name prefix"), - &op_look_for), - - GNUNET_GETOPT_option_flag ('H', - "replay-latest", - gettext_noop ("replay history of messages up to the given --limit"), - &op_replay_latest), - - GNUNET_GETOPT_option_flag ('N', - "host-reconnect", - gettext_noop ("reconnect to a previously created place"), - &op_host_reconnect), - - GNUNET_GETOPT_option_flag ('P', - "host-announce", - gettext_noop ("publish something to a place we are hosting"), - &op_host_announce), - - GNUNET_GETOPT_option_flag ('R', - "guest-reconnect", - gettext_noop ("reconnect to a previously entered place"), - &op_guest_reconnect), - - GNUNET_GETOPT_option_flag ('S', - "look-at", - gettext_noop ("search for state matching exact name"), - &op_look_at), - - GNUNET_GETOPT_option_flag ('T', - "guest-talk", - gettext_noop ("submit something to somebody's place"), - &op_guest_talk), - - GNUNET_GETOPT_option_flag ('U', - "status", - gettext_noop ("list of egos and subscribed places"), - &op_status), - - GNUNET_GETOPT_option_flag ('X', - "replay", - gettext_noop ("extract and replay history between message IDs --start and --until"), - &op_replay), - - - /* options */ - - GNUNET_GETOPT_option_string ('a', - "app", - "APPLICATION_ID", - gettext_noop ("application ID to use when connecting"), - &opt_app), - - GNUNET_GETOPT_option_string ('d', - "data", - "DATA", - gettext_noop ("message body or state value"), - &opt_data), - - GNUNET_GETOPT_option_string ('e', - "ego", - "NAME|PUBKEY", - gettext_noop ("name or public key of ego"), - &opt_ego), - - GNUNET_GETOPT_option_flag ('f', - "follow", - gettext_noop ("wait for incoming messages"), - &opt_follow), - - GNUNET_GETOPT_option_string ('g', - "gns", - "GNS_NAME", - gettext_noop ("GNS name"), - &opt_gns), - - GNUNET_GETOPT_option_string ('i', - "peer", - "PEER_ID", - gettext_noop ("peer ID for --guest-enter"), - &opt_peer), - - GNUNET_GETOPT_option_string ('k', - "name", - "VAR_NAME", - gettext_noop ("name (key) to query from state"), - &opt_name), - - GNUNET_GETOPT_option_string ('m', - "method", - "METHOD_NAME", - gettext_noop ("method name"), - &opt_method), - - GNUNET_GETOPT_option_ulong ('n', - "limit", - NULL, - gettext_noop ("number of messages to replay from history"), - &opt_limit), - - GNUNET_GETOPT_option_string ('p', - "place", - "PUBKEY", - gettext_noop ("key address of place"), - &opt_place), - - GNUNET_GETOPT_option_ulong ('s', - "start", - NULL, - gettext_noop ("start message ID for history replay"), - &opt_start), - - GNUNET_GETOPT_option_flag ('w', - "welcome", - gettext_noop ("respond to entry requests by admitting all guests"), - &opt_welcome), - - GNUNET_GETOPT_option_ulong ('u', - "until", - NULL, - gettext_noop ("end message ID for history replay"), - &opt_until), - - GNUNET_GETOPT_option_flag ('y', - "deny", - gettext_noop ("respond to entry requests by refusing all guests"), - &opt_deny), - - GNUNET_GETOPT_OPTION_END - }; - - if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) - return 2; - - const char *help = - _ ("gnunet-social - Interact with the social service: enter/leave, send/receive messages, access history and state.\n"); - const char *usage = - "gnunet-social [--status]\n" - "\n" - "gnunet-social --host-enter --ego [--follow] [--welcome | --deny]\n" - "gnunet-social --host-reconnect --place [--follow] [--welcome | --deny]\n" - "gnunet-social --host-leave --place \n" - "gnunet-social --host-assign --place --name --data \n" -// FIXME: some state ops not implemented yet (no hurry) -// "gnunet-social --host-augment --place --name --data \n" -// "gnunet-social --host-diminish --place --name --data \n" -// "gnunet-social --host-set --place --name --data \n" - "gnunet-social --host-announce --place --method --data \n" - "\n" - "gnunet-social --guest-enter --place --peer --ego [--follow]\n" - "gnunet-social --guest-enter --gns --ego [--follow]\n" - "gnunet-social --guest-reconnect --place [--follow]\n" - "gnunet-social --guest-leave --place \n" - "gnunet-social --guest-talk --place --method --data \n" - "\n" - "gnunet-social --replay --place --start --until [--method ]\n" - "gnunet-social --replay-latest --place --limit [--method ]\n" - "\n" - "gnunet-social --look-at --place --name \n" - "gnunet-social --look-for --place --name \n"; - - res = GNUNET_PROGRAM_run (argc, argv, help, usage, options, &run, NULL); - - GNUNET_free ((void *) argv); - - if (GNUNET_OK == res) - return ret; - else - return 1; -} diff --git a/src/social/social.conf.in b/src/social/social.conf.in deleted file mode 100644 index 3fe754c80..000000000 --- a/src/social/social.conf.in +++ /dev/null @@ -1,15 +0,0 @@ -[social] -START_ON_DEMAND = @START_ON_DEMAND@ -BINARY = gnunet-service-social -RUN_PER_USER = YES - -UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-social.sock -UNIX_MATCH_UID = YES -UNIX_MATCH_GID = YES - -@UNIXONLY@PORT = 2116 -HOSTNAME = localhost -ACCEPT_FROM = 127.0.0.1; -ACCEPT_FROM6 = ::1; - -DATA_HOME = $GNUNET_DATA_HOME/social diff --git a/src/social/social.h b/src/social/social.h deleted file mode 100644 index 73f73f651..000000000 --- a/src/social/social.h +++ /dev/null @@ -1,292 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @file social/social.h - * @brief Common type definitions for the Social service and API. - * @author Gabor X Toth - */ - -#ifndef SOCIAL_H -#define SOCIAL_H - -#include "platform.h" -#include "gnunet_social_service.h" - -enum MessageState -{ - MSG_STATE_START = 0, - MSG_STATE_HEADER = 1, - MSG_STATE_METHOD = 2, - MSG_STATE_MODIFIER = 3, - MSG_STATE_MOD_CONT = 4, - MSG_STATE_DATA = 5, - MSG_STATE_END = 6, - MSG_STATE_CANCEL = 7, - MSG_STATE_ERROR = 8, -}; - - -GNUNET_NETWORK_STRUCT_BEGIN - -/**** library -> service ****/ - - -struct AppConnectRequest -{ - /** - * Type: GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT - */ - struct GNUNET_MessageHeader header; - - /* Followed by char *app_id */ -}; - - -struct AppDetachRequest -{ - /** - * Type: GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH - */ - struct GNUNET_MessageHeader header; - - /** - * Public key of place. - */ - struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; - - /** - * Public key of ego. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; - - /** - * Operation ID. - */ - uint64_t op_id GNUNET_PACKED; -}; - - -struct MsgProcRequest -{ - /** - * Type: GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_SET - */ - struct GNUNET_MessageHeader header; - - /** - * @see enum GNUNET_SOCIAL_MsgProcFlags - */ - uint32_t flags; - - /* Followed by char *method_prefix */ -}; - - -struct HostEnterRequest -{ - /** - * Type: GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER - */ - struct GNUNET_MessageHeader header; - - uint32_t policy GNUNET_PACKED; - - struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; - - struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; - - struct GNUNET_CRYPTO_EddsaPrivateKey place_key; - - /* Followed by char *app_id */ -}; - - -struct GuestEnterRequest -{ - /** - * Type: GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER - */ - struct GNUNET_MessageHeader header; - - uint32_t relay_count GNUNET_PACKED; - - struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; - - struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; - - struct GNUNET_PeerIdentity origin; - - uint32_t flags GNUNET_PACKED; - - /* Followed by char *app_id */ - /* Followed by struct GNUNET_PeerIdentity relays[relay_count] */ - /* Followed by struct GNUNET_MessageHeader *join_msg */ -}; - - -/** Compatible parts of HostEnterRequest and GuestEnterRequest */ -struct PlaceEnterRequest -{ - struct GNUNET_MessageHeader header; - - uint32_t reserved GNUNET_PACKED; - - struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; - - struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; -}; - - -struct EgoPlacePublicKey -{ - struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; - struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; -}; - - -struct GuestEnterByNameRequest -{ - /** - * Type: GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME - */ - struct GNUNET_MessageHeader header; - - struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; - - /* Followed by char *app_id */ - /* Followed by char *gns_name */ - /* Followed by char *password */ - /* Followed by struct GNUNET_MessageHeader *join_msg */ -}; - - -struct ZoneAddPlaceRequest -{ - struct GNUNET_MessageHeader header; - - uint32_t relay_count GNUNET_PACKED; - - /** - * Operation ID. - */ - uint64_t op_id; - - /** - * Expiration time: absolute value in us. - */ - uint64_t expiration_time; - - struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; - - struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; - - struct GNUNET_PeerIdentity origin; - - /* Followed by const char *name */ - /* Followed by const char *password */ - /* Followed by struct GNUNET_PeerIdentity *relays[relay_count] */ -}; - - -struct ZoneAddNymRequest -{ - struct GNUNET_MessageHeader header; - - /** - * Operation ID. - */ - uint64_t op_id; - - /** - * Expiration time: absolute value in us. - */ - uint64_t expiration_time; - - struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; - - struct GNUNET_CRYPTO_EcdsaPublicKey nym_pub_key; - - /* Followed by const char *name */ -}; - - -/**** service -> library ****/ - - -struct AppEgoMessage -{ - /** - * Type: GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO - */ - struct GNUNET_MessageHeader header; - - /** - * Public key of ego. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; - - /* Followed by char *name */ -}; - - -struct AppPlaceMessage -{ - /** - * Type: GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE - */ - struct GNUNET_MessageHeader header; - - struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; - - struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; - - uint8_t is_host; - - uint8_t place_state; -}; - - -struct HostEnterAck { - /** - * Type: GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK - */ - struct GNUNET_MessageHeader header; - - /** - * Status code for the operation. - */ - uint32_t result_code GNUNET_PACKED; - - /** - * Last message ID sent to the channel. - */ - uint64_t max_message_id GNUNET_PACKED; - - /** - * Public key of the place. - */ - struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; -}; - - -GNUNET_NETWORK_STRUCT_END - -#endif diff --git a/src/social/social_api.c b/src/social/social_api.c deleted file mode 100644 index 9b9658096..000000000 --- a/src/social/social_api.c +++ /dev/null @@ -1,2827 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @author Gabor X Toth - * - * @file - * Social service; implements social interactions using the PSYC service. - */ - -#include -#include - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_psyc_service.h" -#include "gnunet_psyc_util_lib.h" -#include "gnunet_social_service.h" -#include "social.h" - -#define LOG(kind,...) GNUNET_log_from (kind, "social-api",__VA_ARGS__) - -/** - * Handle for an ego. - */ -struct GNUNET_SOCIAL_Ego -{ - struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; - struct GNUNET_HashCode pub_key_hash; - char *name; -}; - - -/** - * Handle for a pseudonym of another user in the network. - */ -struct GNUNET_SOCIAL_Nym -{ - struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; - struct GNUNET_HashCode pub_key_hash; -}; - - -/** - * Handle for an application. - */ -struct GNUNET_SOCIAL_App -{ - /** - * Configuration to use. - */ - const struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * Client connection to the service. - */ - struct GNUNET_MQ_Handle *mq; - - /** - * Message to send on connect. - */ - struct GNUNET_MQ_Envelope *connect_env; - - /** - * Time to wait until we try to reconnect on failure. - */ - struct GNUNET_TIME_Relative reconnect_delay; - - /** - * Task for reconnecting when the listener fails. - */ - struct GNUNET_SCHEDULER_Task *reconnect_task; - - /** - * Async operations. - */ - struct GNUNET_OP_Handle *op; - - /** - * Function called after disconnected from the service. - */ - GNUNET_ContinuationCallback disconnect_cb; - - /** - * Closure for @a disconnect_cb. - */ - void *disconnect_cls; - - /** - * Application ID. - */ - char *id; - - /** - * Hash map of all egos. - * pub_key_hash -> struct GNUNET_SOCIAL_Ego * - */ - struct GNUNET_CONTAINER_MultiHashMap *egos; - - GNUNET_SOCIAL_AppEgoCallback ego_cb; - GNUNET_SOCIAL_AppHostPlaceCallback host_cb; - GNUNET_SOCIAL_AppGuestPlaceCallback guest_cb; - GNUNET_SOCIAL_AppConnectedCallback connected_cb; - void *cb_cls; -}; - - -struct GNUNET_SOCIAL_HostConnection -{ - struct GNUNET_SOCIAL_App *app; - - struct AppPlaceMessage plc_msg; -}; - - -struct GNUNET_SOCIAL_GuestConnection -{ - struct GNUNET_SOCIAL_App *app; - - struct AppPlaceMessage plc_msg; -}; - - -/** - * Handle for a place where social interactions happen. - */ -struct GNUNET_SOCIAL_Place -{ - /** - * Configuration to use. - */ - const struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * Client connection to the service. - */ - struct GNUNET_MQ_Handle *mq; - - /** - * Message to send on connect. - */ - struct GNUNET_MQ_Envelope *connect_env; - - /** - * Time to wait until we try to reconnect on failure. - */ - struct GNUNET_TIME_Relative reconnect_delay; - - /** - * Task for reconnecting when the listener fails. - */ - struct GNUNET_SCHEDULER_Task *reconnect_task; - - /** - * Async operations. - */ - struct GNUNET_OP_Handle *op; - - /** - * Transmission handle. - */ - struct GNUNET_PSYC_TransmitHandle *tmit; - - /** - * Slicer for processing incoming messages. - */ - struct GNUNET_PSYC_Slicer *slicer; - - // FIXME: do we need is_disconnecing like on the psyc and multicast APIs? - /** - * Function called after disconnected from the service. - */ - GNUNET_ContinuationCallback disconnect_cb; - - /** - * Closure for @a disconnect_cb. - */ - void *disconnect_cls; - - /** - * Public key of the place. - */ - struct GNUNET_CRYPTO_EddsaPublicKey pub_key; - - /** - * Public key of the ego. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; - - /** - * Does this place belong to a host (#GNUNET_YES) or guest (#GNUNET_NO)? - */ - uint8_t is_host; -}; - - -/** - * Host handle for a place that we entered. - */ -struct GNUNET_SOCIAL_Host -{ - struct GNUNET_SOCIAL_Place plc; - - /** - * Slicer for processing incoming messages from guests. - */ - struct GNUNET_PSYC_Slicer *slicer; - - GNUNET_SOCIAL_HostEnterCallback enter_cb; - - GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb; - - GNUNET_SOCIAL_FarewellCallback farewell_cb; - - /** - * Closure for callbacks. - */ - void *cb_cls; - - struct GNUNET_SOCIAL_Nym *notice_place_leave_nym; - struct GNUNET_PSYC_Environment *notice_place_leave_env; -}; - - -/** - * Guest handle for place that we entered. - */ -struct GNUNET_SOCIAL_Guest -{ - struct GNUNET_SOCIAL_Place plc; - - GNUNET_SOCIAL_GuestEnterCallback enter_cb; - - GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb; - - /** - * Closure for callbacks. - */ - void *cb_cls; -}; - - -/** - * Hash map of all nyms. - * pub_key_hash -> struct GNUNET_SOCIAL_Nym * - */ -struct GNUNET_CONTAINER_MultiHashMap *nyms; - - -/** - * Handle for an announcement request. - */ -struct GNUNET_SOCIAL_Announcement -{ - -}; - - -/** - * A talk request. - */ -struct GNUNET_SOCIAL_TalkRequest -{ - -}; - - -/** - * A history lesson. - */ -struct GNUNET_SOCIAL_HistoryRequest -{ - /** - * Place. - */ - struct GNUNET_SOCIAL_Place *plc; - - /** - * Operation ID. - */ - uint64_t op_id; - - /** - * Slicer for processing incoming messages. - */ - struct GNUNET_PSYC_Slicer *slicer; - - /** - * Function to call when the operation finished. - */ - GNUNET_ResultCallback result_cb; - - /** - * Closure for @a result_cb. - */ - void *cls; -}; - - -struct GNUNET_SOCIAL_LookHandle -{ - /** - * Place. - */ - struct GNUNET_SOCIAL_Place *plc; - - /** - * Operation ID. - */ - uint64_t op_id; - - /** - * State variable result callback. - */ - GNUNET_PSYC_StateVarCallback var_cb; - - /** - * Function to call when the operation finished. - */ - GNUNET_ResultCallback result_cb; - - /** - * Name of current modifier being received. - */ - char *mod_name; - - /** - * Size of current modifier value being received. - */ - size_t mod_value_size; - - /** - * Remaining size of current modifier value still to be received. - */ - size_t mod_value_remaining; - - /** - * Closure for @a result_cb. - */ - void *cls; -}; - - -struct ZoneAddPlaceHandle -{ - GNUNET_ResultCallback result_cb; - void *result_cls; -}; - - -struct ZoneAddNymHandle -{ - GNUNET_ResultCallback result_cb; - void *result_cls; -}; - - -/*** CLEANUP / DISCONNECT ***/ - - -static void -host_cleanup (struct GNUNET_SOCIAL_Host *hst) -{ - if (NULL != hst->slicer) - { - GNUNET_PSYC_slicer_destroy (hst->slicer); - hst->slicer = NULL; - } - GNUNET_free (hst); -} - - -static void -guest_cleanup (struct GNUNET_SOCIAL_Guest *gst) -{ - GNUNET_free (gst); -} - - -static void -place_cleanup (struct GNUNET_SOCIAL_Place *plc) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "cleaning up place %p\n", - plc); - if (NULL != plc->tmit) - { - GNUNET_PSYC_transmit_destroy (plc->tmit); - plc->tmit = NULL; - } - if (NULL != plc->connect_env) - { - GNUNET_MQ_discard (plc->connect_env); - plc->connect_env = NULL; - } - if (NULL != plc->mq) - { - GNUNET_MQ_destroy (plc->mq); - plc->mq = NULL; - } - if (NULL != plc->disconnect_cb) - { - plc->disconnect_cb (plc->disconnect_cls); - plc->disconnect_cb = NULL; - } - - (GNUNET_YES == plc->is_host) - ? host_cleanup ((struct GNUNET_SOCIAL_Host *) plc) - : guest_cleanup ((struct GNUNET_SOCIAL_Guest *) plc); -} - - -static void -place_disconnect (struct GNUNET_SOCIAL_Place *plc) -{ - place_cleanup (plc); -} - - -/*** NYM ***/ - -static struct GNUNET_SOCIAL_Nym * -nym_get_or_create (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub_key) -{ - struct GNUNET_SOCIAL_Nym *nym = NULL; - struct GNUNET_HashCode pub_key_hash; - - if (NULL == pub_key) - return NULL; - - GNUNET_CRYPTO_hash (pub_key, sizeof (*pub_key), &pub_key_hash); - - if (NULL == nyms) - nyms = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); - else - nym = GNUNET_CONTAINER_multihashmap_get (nyms, &pub_key_hash); - - if (NULL == nym) - { - nym = GNUNET_new (struct GNUNET_SOCIAL_Nym); - nym->pub_key = *pub_key; - nym->pub_key_hash = pub_key_hash; - GNUNET_CONTAINER_multihashmap_put (nyms, &nym->pub_key_hash, nym, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - } - return nym; -} - - -static void -nym_destroy (struct GNUNET_SOCIAL_Nym *nym) -{ - GNUNET_CONTAINER_multihashmap_remove (nyms, &nym->pub_key_hash, nym); - GNUNET_free (nym); -} - - -/*** MESSAGE HANDLERS ***/ - -/** _notice_place_leave from guests */ - -static void -host_recv_notice_place_leave_method (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_PSYC_MessageMethod *meth, - uint64_t message_id, - const char *method_name) -{ - struct GNUNET_SOCIAL_Host *hst = cls; - - if (0 == memcmp (&(struct GNUNET_CRYPTO_EcdsaPublicKey) {}, - &msg->slave_pub_key, sizeof (msg->slave_pub_key))) - return; - - struct GNUNET_SOCIAL_Nym *nym = nym_get_or_create (&msg->slave_pub_key); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Host received method for message ID %" PRIu64 " from nym %s: %s\n", - message_id, GNUNET_h2s (&nym->pub_key_hash), method_name); - - hst->notice_place_leave_nym = (struct GNUNET_SOCIAL_Nym *) nym; - hst->notice_place_leave_env = GNUNET_PSYC_env_create (); - - char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&hst->notice_place_leave_nym->pub_key); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "_notice_place_leave: got method from nym %s (%s).\n", - GNUNET_h2s (&hst->notice_place_leave_nym->pub_key_hash), str); - GNUNET_free (str); -} - - -static void -host_recv_notice_place_leave_modifier (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg, - uint64_t message_id, - enum GNUNET_PSYC_Operator oper, - const char *name, - const void *value, - uint16_t value_size, - uint16_t full_value_size) -{ - struct GNUNET_SOCIAL_Host *hst = cls; - if (NULL == hst->notice_place_leave_env) - return; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Host received modifier for _notice_place_leave message with ID %" PRIu64 ":\n" - "%c%s: %.*s\n", - message_id, oper, name, value_size, (const char *) value); - - /* skip _nym, it's added later in eom() */ - if (0 == memcmp (name, "_nym", sizeof ("_nym")) - || 0 == memcmp (name, "_nym_", sizeof ("_nym_") - 1)) - return; - - GNUNET_PSYC_env_add (hst->notice_place_leave_env, - GNUNET_PSYC_OP_SET, name, value, value_size); -} - - -static void -host_recv_notice_place_leave_eom (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg, - uint64_t message_id, - uint8_t is_cancelled) -{ - struct GNUNET_SOCIAL_Host *hst = cls; - if (NULL == hst->notice_place_leave_env) - return; - - char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&hst->notice_place_leave_nym->pub_key); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "_notice_place_leave: got EOM from nym %s (%s).\n", - GNUNET_h2s (&hst->notice_place_leave_nym->pub_key_hash), str); - GNUNET_free (str); - - if (GNUNET_YES != is_cancelled) - { - if (NULL != hst->farewell_cb) - hst->farewell_cb (hst->cb_cls, hst->notice_place_leave_nym, - hst->notice_place_leave_env); - /* announce leaving guest to place */ - GNUNET_PSYC_env_add (hst->notice_place_leave_env, GNUNET_PSYC_OP_SET, - "_nym", hst->notice_place_leave_nym, - sizeof (*hst->notice_place_leave_nym)); - GNUNET_SOCIAL_host_announce (hst, "_notice_place_leave", - hst->notice_place_leave_env, - NULL, NULL, GNUNET_SOCIAL_ANNOUNCE_NONE); - nym_destroy (hst->notice_place_leave_nym); - } - GNUNET_PSYC_env_destroy (hst->notice_place_leave_env); - hst->notice_place_leave_env = NULL; -} - - -/*** PLACE ***/ - - -static int -check_place_result (void *cls, - const struct GNUNET_OperationResultMessage *res) -{ - uint16_t size = ntohs (res->header.size); - if (size < sizeof (*res)) - { /* Error, message too small. */ - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -static void -handle_place_result (void *cls, - const struct GNUNET_OperationResultMessage *res) -{ - struct GNUNET_SOCIAL_Place *plc = cls; - - uint16_t size = ntohs (res->header.size); - uint16_t data_size = size - sizeof (*res); - const char *data = (0 < data_size) ? (const char *) &res[1] : NULL; - - GNUNET_OP_result (plc->op, GNUNET_ntohll (res->op_id), - GNUNET_ntohll (res->result_code), - data, data_size, NULL); -} - - -static int -check_app_result (void *cls, - const struct GNUNET_OperationResultMessage *res) -{ - uint16_t size = ntohs (res->header.size); - if (size < sizeof (*res)) - { /* Error, message too small. */ - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -static void -handle_app_result (void *cls, - const struct GNUNET_OperationResultMessage *res) -{ - struct GNUNET_SOCIAL_App *app = cls; - - uint16_t size = ntohs (res->header.size); - uint16_t data_size = size - sizeof (*res); - const char *data = (0 < data_size) ? (const char *) &res[1] : NULL; - - GNUNET_OP_result (app->op, GNUNET_ntohll (res->op_id), - GNUNET_ntohll (res->result_code), - data, data_size, NULL); -} - - -static void -op_recv_history_result (void *cls, int64_t result, - const void *err_msg, uint16_t err_msg_size) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received history replay result: %" PRId64 ".\n", result); - - struct GNUNET_SOCIAL_HistoryRequest *hist = cls; - - if (NULL != hist->result_cb) - hist->result_cb (hist->cls, result, err_msg, err_msg_size); - - GNUNET_free (hist); -} - - -static void -op_recv_state_result (void *cls, int64_t result, - const void *err_msg, uint16_t err_msg_size) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received state request result: %" PRId64 ".\n", result); - - struct GNUNET_SOCIAL_LookHandle *look = cls; - - if (NULL != look->result_cb) - look->result_cb (look->cls, result, err_msg, err_msg_size); - - GNUNET_free (look); -} - - -static int -check_place_history_result (void *cls, - const struct GNUNET_OperationResultMessage *res) -{ - struct GNUNET_PSYC_MessageHeader * - pmsg = (struct GNUNET_PSYC_MessageHeader *) GNUNET_MQ_extract_nested_mh (res); - uint16_t size = ntohs (res->header.size); - - if (NULL == pmsg || size < sizeof (*res) + sizeof (*pmsg)) - { /* Error, message too small. */ - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -static void -handle_place_history_result (void *cls, - const struct GNUNET_OperationResultMessage *res) -{ - struct GNUNET_SOCIAL_Place *plc = cls; - struct GNUNET_PSYC_MessageHeader * - pmsg = (struct GNUNET_PSYC_MessageHeader *) GNUNET_MQ_extract_nested_mh (res); - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "%p Received historic fragment for message #%" PRIu64 ".\n", - plc, GNUNET_ntohll (pmsg->message_id)); - - GNUNET_ResultCallback result_cb = NULL; - struct GNUNET_SOCIAL_HistoryRequest *hist = NULL; - - if (GNUNET_YES != GNUNET_OP_get (plc->op, - GNUNET_ntohll (res->op_id), - &result_cb, (void *) &hist, NULL)) - { /* Operation not found. */ - LOG (GNUNET_ERROR_TYPE_WARNING, - "%p Replay operation not found for historic fragment of message #%" - PRIu64 ".\n", - plc, GNUNET_ntohll (pmsg->message_id)); - return; - } - - GNUNET_PSYC_slicer_message (hist->slicer, - (const struct GNUNET_PSYC_MessageHeader *) pmsg); -} - - -static int -check_place_state_result (void *cls, - const struct GNUNET_OperationResultMessage *res) -{ - const struct GNUNET_MessageHeader *mod = GNUNET_MQ_extract_nested_mh (res); - if (NULL == mod) - { - GNUNET_break_op (0); - LOG (GNUNET_ERROR_TYPE_WARNING, - "Invalid modifier in state result\n"); - return GNUNET_SYSERR; - } - - uint16_t size = ntohs (res->header.size); - uint16_t mod_size = ntohs (mod->size); - if (size - sizeof (*res) != mod_size) - { - GNUNET_break_op (0); - LOG (GNUNET_ERROR_TYPE_WARNING, - "Invalid modifier size in state result: %u - %u != %u\n", - ntohs (res->header.size), sizeof (*res), mod_size); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -static void -handle_place_state_result (void *cls, - const struct GNUNET_OperationResultMessage *res) -{ - struct GNUNET_SOCIAL_Place *plc = cls; - - GNUNET_ResultCallback result_cb = NULL; - struct GNUNET_SOCIAL_LookHandle *look = NULL; - - if (GNUNET_YES != GNUNET_OP_get (plc->op, - GNUNET_ntohll (res->op_id), - &result_cb, (void *) &look, NULL)) - { /* Operation not found. */ - return; - } - - const struct GNUNET_MessageHeader *mod = GNUNET_MQ_extract_nested_mh (res); - uint16_t mod_size = ntohs (mod->size); - - switch (ntohs (mod->type)) - { - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: - { - const struct GNUNET_PSYC_MessageModifier * - pmod = (const struct GNUNET_PSYC_MessageModifier *) mod; - - const char *name = (const char *) &pmod[1]; - uint16_t name_size = ntohs (pmod->name_size); - if (0 == name_size - || mod_size - sizeof (*pmod) < name_size - || '\0' != name[name_size - 1]) - { - GNUNET_break_op (0); - LOG (GNUNET_ERROR_TYPE_WARNING, - "Invalid modifier name in state result\n"); - return; - } - look->mod_value_size = ntohs (pmod->value_size); - look->var_cb (look->cls, mod, name, name + name_size, - mod_size - sizeof (*mod) - name_size, - look->mod_value_size); - if (look->mod_value_size > mod_size - sizeof (*mod) - name_size) - { - look->mod_value_remaining = look->mod_value_size; - look->mod_name = GNUNET_malloc (name_size); - GNUNET_memcpy (look->mod_name, name, name_size); - } - break; - } - - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: - look->var_cb (look->cls, mod, look->mod_name, (const char *) &mod[1], - mod_size - sizeof (*mod), look->mod_value_size); - look->mod_value_remaining -= mod_size - sizeof (*mod); - if (0 == look->mod_value_remaining) - { - GNUNET_free (look->mod_name); - } - break; - } -} - - -static void -handle_place_message_ack (void *cls, - const struct GNUNET_MessageHeader *msg) -{ - struct GNUNET_SOCIAL_Place *plc = cls; - - GNUNET_PSYC_transmit_got_ack (plc->tmit); -} - - -static int -check_place_message (void *cls, - const struct GNUNET_PSYC_MessageHeader *pmsg) -{ - return GNUNET_OK; -} - - -static void -handle_place_message (void *cls, - const struct GNUNET_PSYC_MessageHeader *pmsg) -{ - struct GNUNET_SOCIAL_Place *plc = cls; - - GNUNET_PSYC_slicer_message (plc->slicer, pmsg); -} - - -static int -check_host_message (void *cls, - const struct GNUNET_PSYC_MessageHeader *pmsg) -{ - return GNUNET_OK; -} - - -static void -handle_host_message (void *cls, - const struct GNUNET_PSYC_MessageHeader *pmsg) -{ - struct GNUNET_SOCIAL_Host *hst = cls; - - GNUNET_PSYC_slicer_message (hst->slicer, pmsg); - GNUNET_PSYC_slicer_message (hst->plc.slicer, pmsg); -} - - -static void -handle_host_enter_ack (void *cls, - const struct HostEnterAck *hack) -{ - struct GNUNET_SOCIAL_Host *hst = cls; - - hst->plc.pub_key = hack->place_pub_key; - - int32_t result = ntohl (hack->result_code); - if (NULL != hst->enter_cb) - hst->enter_cb (hst->cb_cls, result, &hack->place_pub_key, - GNUNET_ntohll (hack->max_message_id)); -} - - -static int -check_host_enter_request (void *cls, - const struct GNUNET_PSYC_JoinRequestMessage *req) -{ - return GNUNET_OK; -} - - -static void -handle_host_enter_request (void *cls, - const struct GNUNET_PSYC_JoinRequestMessage *req) -{ - struct GNUNET_SOCIAL_Host *hst = cls; - - if (NULL == hst->answer_door_cb) - return; - - const char *method_name = NULL; - struct GNUNET_PSYC_Environment *env = NULL; - struct GNUNET_PSYC_MessageHeader *entry_pmsg = NULL; - const void *data = NULL; - uint16_t data_size = 0; - char *str; - const struct GNUNET_PSYC_Message *join_msg = NULL; - - do - { - if (sizeof (*req) + sizeof (*join_msg) <= ntohs (req->header.size)) - { - join_msg = (struct GNUNET_PSYC_Message *) GNUNET_MQ_extract_nested_mh (req); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received join_msg of type %u and size %u.\n", - ntohs (join_msg->header.type), ntohs (join_msg->header.size)); - - env = GNUNET_PSYC_env_create (); - entry_pmsg = GNUNET_PSYC_message_header_create_from_psyc (join_msg); - if (GNUNET_OK != GNUNET_PSYC_message_parse (entry_pmsg, &method_name, env, - &data, &data_size)) - { - GNUNET_break_op (0); - str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&req->slave_pub_key); - LOG (GNUNET_ERROR_TYPE_WARNING, - "Ignoring invalid entry request from nym %s.\n", - str); - GNUNET_free (str); - break; - } - } - - struct GNUNET_SOCIAL_Nym *nym = nym_get_or_create (&req->slave_pub_key); - hst->answer_door_cb (hst->cb_cls, nym, method_name, env, - data, data_size); - } while (0); - - if (NULL != env) - GNUNET_PSYC_env_destroy (env); - if (NULL != entry_pmsg) - GNUNET_free (entry_pmsg); -} - - -static void -handle_guest_enter_ack (void *cls, - const struct GNUNET_PSYC_CountersResultMessage *cres) -{ - struct GNUNET_SOCIAL_Guest *gst = cls; - - int32_t result = ntohl (cres->result_code); - if (NULL != gst->enter_cb) - gst->enter_cb (gst->cb_cls, result, &gst->plc.pub_key, - GNUNET_ntohll (cres->max_message_id)); -} - - -static int -check_guest_enter_decision (void *cls, - const struct GNUNET_PSYC_JoinDecisionMessage *dcsn) -{ - return GNUNET_OK; -} - - -static void -handle_guest_enter_decision (void *cls, - const struct GNUNET_PSYC_JoinDecisionMessage *dcsn) -{ - struct GNUNET_SOCIAL_Guest *gst = cls; - - struct GNUNET_PSYC_Message *pmsg = NULL; - if (ntohs (dcsn->header.size) > sizeof (*dcsn)) - pmsg = (struct GNUNET_PSYC_Message *) GNUNET_MQ_extract_nested_mh (dcsn); - - if (NULL != gst->entry_dcsn_cb) - gst->entry_dcsn_cb (gst->cb_cls, ntohl (dcsn->is_admitted), pmsg); -} - - -static int -check_app_ego (void *cls, - const struct AppEgoMessage *emsg) -{ - return GNUNET_OK; -} - - -static void -handle_app_ego (void *cls, - const struct AppEgoMessage *emsg) -{ - struct GNUNET_SOCIAL_App *app = cls; - - uint16_t name_size = ntohs (emsg->header.size) - sizeof (*emsg); - - struct GNUNET_HashCode ego_pub_hash; - GNUNET_CRYPTO_hash (&emsg->ego_pub_key, sizeof (emsg->ego_pub_key), - &ego_pub_hash); - - struct GNUNET_SOCIAL_Ego * - ego = GNUNET_CONTAINER_multihashmap_get (app->egos, &ego_pub_hash); - if (NULL == ego) - { - ego = GNUNET_malloc (sizeof (*ego)); - ego->pub_key = emsg->ego_pub_key; - ego->name = GNUNET_malloc (name_size); - GNUNET_memcpy (ego->name, &emsg[1], name_size); - } - else - { - ego->name = GNUNET_realloc (ego->name, name_size); - GNUNET_memcpy (ego->name, &emsg[1], name_size); - } - - GNUNET_CONTAINER_multihashmap_put (app->egos, &ego_pub_hash, ego, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); - - if (NULL != app->ego_cb) - app->ego_cb (app->cb_cls, ego, &ego->pub_key, ego->name); -} - - -static void -handle_app_ego_end (void *cls, - const struct GNUNET_MessageHeader *msg) -{ - //struct GNUNET_SOCIAL_App *app = cls; -} - - -static int -check_app_place (void *cls, - const struct AppPlaceMessage *pmsg) -{ - return GNUNET_OK; -} - - -static void -handle_app_place (void *cls, - const struct AppPlaceMessage *pmsg) -{ - struct GNUNET_SOCIAL_App *app = cls; - - if ((GNUNET_YES == pmsg->is_host && NULL == app->host_cb) - || (GNUNET_NO == pmsg->is_host && NULL == app->guest_cb)) - return; - - struct GNUNET_HashCode ego_pub_hash; - GNUNET_CRYPTO_hash (&pmsg->ego_pub_key, sizeof (pmsg->ego_pub_key), - &ego_pub_hash); - struct GNUNET_SOCIAL_Ego * - ego = GNUNET_CONTAINER_multihashmap_get (app->egos, &ego_pub_hash); - if (NULL == ego) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failure to obtain ego %s.\n", - GNUNET_h2s (&ego_pub_hash)); - GNUNET_break (0); - return; - } - - if (GNUNET_YES == pmsg->is_host) - { - if (NULL != app->host_cb) { - struct GNUNET_SOCIAL_HostConnection *hconn = GNUNET_malloc (sizeof (*hconn)); - hconn->app = app; - hconn->plc_msg = *pmsg; - app->host_cb (app->cb_cls, hconn, ego, &pmsg->place_pub_key, pmsg->place_state); - GNUNET_free (hconn); - } - } - else if (NULL != app->guest_cb) - { - struct GNUNET_SOCIAL_GuestConnection *gconn = GNUNET_malloc (sizeof (*gconn)); - gconn->app = app; - gconn->plc_msg = *pmsg; - app->guest_cb (app->cb_cls, gconn, ego, &pmsg->place_pub_key, pmsg->place_state); - GNUNET_free (gconn); - } -} - - -static void -handle_app_place_end (void *cls, - const struct GNUNET_MessageHeader *msg) -{ - struct GNUNET_SOCIAL_App *app = cls; - - if (NULL != app->connected_cb) - app->connected_cb (app->cb_cls); -} - - -/** - * Handler for a #GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE_ACK message received - * from the social service. - * - * @param cls the place of type `struct GNUNET_SOCIAL_Place` - * @param msg the message received from the service - */ -static void -handle_place_leave_ack (void *cls, - const struct GNUNET_MessageHeader *msg) -{ - struct GNUNET_SOCIAL_Place *plc = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%s left place %p\n", - plc->is_host ? "host" : "guest", - plc); - place_disconnect (plc); -} - - -/*** HOST ***/ - - -static void -host_connect (struct GNUNET_SOCIAL_Host *hst); - - -static void -host_reconnect (void *cls) -{ - host_connect (cls); -} - - -/** - * Host client disconnected from service. - * - * Reconnect after backoff period. - */ -static void -host_disconnected (void *cls, enum GNUNET_MQ_Error error) -{ - struct GNUNET_SOCIAL_Host *hst = cls; - struct GNUNET_SOCIAL_Place *plc = &hst->plc; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Host client disconnected (%d), re-connecting\n", - (int) error); - if (NULL != plc->tmit) - { - GNUNET_PSYC_transmit_destroy (plc->tmit); - plc->tmit = NULL; - } - if (NULL != plc->mq) - { - GNUNET_MQ_destroy (plc->mq); - plc->mq = NULL; - } - - plc->reconnect_task = GNUNET_SCHEDULER_add_delayed (plc->reconnect_delay, - host_reconnect, - hst); - plc->reconnect_delay = GNUNET_TIME_STD_BACKOFF (plc->reconnect_delay); -} - - -static void -host_connect (struct GNUNET_SOCIAL_Host *hst) -{ - struct GNUNET_SOCIAL_Place *plc = &hst->plc; - - struct GNUNET_MQ_MessageHandler handlers[] = { - GNUNET_MQ_hd_fixed_size (host_enter_ack, - GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK, - struct HostEnterAck, - hst), - GNUNET_MQ_hd_fixed_size (place_leave_ack, - GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE_ACK, - struct GNUNET_MessageHeader, - plc), - GNUNET_MQ_hd_var_size (host_enter_request, - GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST, - struct GNUNET_PSYC_JoinRequestMessage, - hst), - GNUNET_MQ_hd_var_size (host_message, - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, - struct GNUNET_PSYC_MessageHeader, - hst), - GNUNET_MQ_hd_fixed_size (place_message_ack, - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK, - struct GNUNET_MessageHeader, - plc), - GNUNET_MQ_hd_var_size (place_history_result, - GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT, - struct GNUNET_OperationResultMessage, - plc), - GNUNET_MQ_hd_var_size (place_state_result, - GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT, - struct GNUNET_OperationResultMessage, - plc), - GNUNET_MQ_hd_var_size (place_result, - GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE, - struct GNUNET_OperationResultMessage, - plc), - GNUNET_MQ_handler_end () - }; - - plc->mq = GNUNET_CLIENT_connect (plc->cfg, "social", - handlers, host_disconnected, hst); - GNUNET_assert (NULL != plc->mq); - plc->tmit = GNUNET_PSYC_transmit_create (plc->mq); - - GNUNET_MQ_send_copy (plc->mq, plc->connect_env); -} - - -/** - * Enter a place as host. - * - * A place is created upon first entering, and it is active until permanently - * left using GNUNET_SOCIAL_host_leave(). - * - * @param app - * Application handle. - * @param ego - * Identity of the host. - * @param policy - * Policy specifying entry and history restrictions for the place. - * @param slicer - * Slicer to handle incoming messages. - * @param enter_cb - * Function called when the place is entered and ready to use. - * @param answer_door_cb - * Function to handle new nyms that want to enter. - * @param farewell_cb - * Function to handle departing nyms. - * @param cls - * Closure for the callbacks. - * - * @return Handle for the host. This handle contains the pubkey. - */ -struct GNUNET_SOCIAL_Host * -GNUNET_SOCIAL_host_enter (const struct GNUNET_SOCIAL_App *app, - const struct GNUNET_SOCIAL_Ego *ego, - enum GNUNET_PSYC_Policy policy, - struct GNUNET_PSYC_Slicer *slicer, - GNUNET_SOCIAL_HostEnterCallback enter_cb, - GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb, - GNUNET_SOCIAL_FarewellCallback farewell_cb, - void *cls) -{ - struct GNUNET_SOCIAL_Host *hst = GNUNET_malloc (sizeof (*hst)); - struct GNUNET_SOCIAL_Place *plc = &hst->plc; - - plc->cfg = app->cfg; - plc->is_host = GNUNET_YES; - plc->slicer = slicer; - - hst->enter_cb = enter_cb; - hst->answer_door_cb = answer_door_cb; - hst->farewell_cb = farewell_cb; - hst->cb_cls = cls; - - plc->op = GNUNET_OP_create (); - - hst->slicer = GNUNET_PSYC_slicer_create (); - GNUNET_PSYC_slicer_method_add (hst->slicer, "_notice_place_leave", NULL, - host_recv_notice_place_leave_method, - host_recv_notice_place_leave_modifier, - NULL, host_recv_notice_place_leave_eom, hst); - - uint16_t app_id_size = strlen (app->id) + 1; - struct HostEnterRequest *hreq; - plc->connect_env = GNUNET_MQ_msg_extra (hreq, app_id_size, - GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER); - hreq->policy = policy; - hreq->ego_pub_key = ego->pub_key; - GNUNET_memcpy (&hreq[1], app->id, app_id_size); - - host_connect (hst); - return hst; -} - - -/** - * Reconnect to an already entered place as host. - * - * @param hconn - * Host connection handle. - * @see GNUNET_SOCIAL_app_connect() & GNUNET_SOCIAL_AppHostPlaceCallback() - * @param slicer - * Slicer to handle incoming messages. - * @param enter_cb - * Function called when the place is entered and ready to use. - * @param answer_door_cb - * Function to handle new nyms that want to enter. - * @param farewell_cb - * Function to handle departing nyms. - * @param cls - * Closure for the callbacks. - * - * @return Handle for the host. - */ - struct GNUNET_SOCIAL_Host * -GNUNET_SOCIAL_host_enter_reconnect (struct GNUNET_SOCIAL_HostConnection *hconn, - struct GNUNET_PSYC_Slicer *slicer, - GNUNET_SOCIAL_HostEnterCallback enter_cb, - GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb, - GNUNET_SOCIAL_FarewellCallback farewell_cb, - void *cls) -{ - struct GNUNET_SOCIAL_Host *hst = GNUNET_malloc (sizeof (*hst)); - struct GNUNET_SOCIAL_Place *plc = &hst->plc; - - hst->enter_cb = enter_cb; - hst->answer_door_cb = answer_door_cb; - hst->farewell_cb = farewell_cb; - hst->cb_cls = cls; - - plc->cfg = hconn->app->cfg; - plc->is_host = GNUNET_YES; - plc->slicer = slicer; - plc->pub_key = hconn->plc_msg.place_pub_key; - plc->ego_pub_key = hconn->plc_msg.ego_pub_key; - - plc->op = GNUNET_OP_create (); - - hst->slicer = GNUNET_PSYC_slicer_create (); - GNUNET_PSYC_slicer_method_add (hst->slicer, "_notice_place_leave", NULL, - host_recv_notice_place_leave_method, - host_recv_notice_place_leave_modifier, - NULL, host_recv_notice_place_leave_eom, hst); - - size_t app_id_size = strlen (hconn->app->id) + 1; - struct HostEnterRequest *hreq; - plc->connect_env = GNUNET_MQ_msg_extra (hreq, app_id_size, - GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER); - hreq->place_pub_key = hconn->plc_msg.place_pub_key; - hreq->ego_pub_key = hconn->plc_msg.ego_pub_key; - GNUNET_memcpy (&hreq[1], hconn->app->id, app_id_size); - - host_connect (hst); - return hst; -} - - -/** - * Decision whether to admit @a nym into the place or refuse entry. - * - * @param hst - * Host of the place. - * @param nym - * Handle for the entity that wanted to enter. - * @param is_admitted - * #GNUNET_YES if @a nym is admitted, - * #GNUNET_NO if @a nym is refused entry, - * #GNUNET_SYSERR if we cannot answer the request. - * @param method_name - * Method name for the rejection message. - * @param env - * Environment containing variables for the message, or NULL. - * @param data - * Data for the rejection message to send back. - * @param data_size - * Number of bytes in @a data for method. - * @return #GNUNET_OK on success, - * #GNUNET_SYSERR if the message is too large. - */ -int -GNUNET_SOCIAL_host_entry_decision (struct GNUNET_SOCIAL_Host *hst, - struct GNUNET_SOCIAL_Nym *nym, - int is_admitted, - const struct GNUNET_PSYC_Message *entry_resp) -{ - struct GNUNET_SOCIAL_Place *plc = &hst->plc; - struct GNUNET_PSYC_JoinDecisionMessage *dcsn; - uint16_t entry_resp_size - = (NULL != entry_resp) ? ntohs (entry_resp->header.size) : 0; - - if (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < sizeof (*dcsn) + entry_resp_size) - return GNUNET_SYSERR; - - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (dcsn, entry_resp_size, - GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION); - dcsn->is_admitted = htonl (is_admitted); - dcsn->slave_pub_key = nym->pub_key; - - if (0 < entry_resp_size) - GNUNET_memcpy (&dcsn[1], entry_resp, entry_resp_size); - - GNUNET_MQ_send (plc->mq, env); - return GNUNET_OK; -} - - -/** - * Throw @a nym out of the place. - * - * The @a nym reference will remain valid until the - * #GNUNET_SOCIAL_FarewellCallback is invoked, - * which should be very soon after this call. - * - * @param host - * Host of the place. - * @param nym - * Handle for the entity to be ejected. - * @param env - * Environment for the message or NULL. - */ -void -GNUNET_SOCIAL_host_eject (struct GNUNET_SOCIAL_Host *hst, - const struct GNUNET_SOCIAL_Nym *nym, - struct GNUNET_PSYC_Environment *e) -{ - struct GNUNET_PSYC_Environment *env = e; - if (NULL == env) - env = GNUNET_PSYC_env_create (); - GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET, - "_nym", &nym->pub_key, sizeof (nym->pub_key)); - GNUNET_SOCIAL_host_announce (hst, "_notice_place_leave", env, NULL, NULL, - GNUNET_SOCIAL_ANNOUNCE_NONE); - if (NULL == e) - GNUNET_PSYC_env_destroy (env); -} - - -/** - * Get the public key of @a ego. - * - * @param ego - * Ego. - * - * @return Public key of ego. - */ -const struct GNUNET_CRYPTO_EcdsaPublicKey * -GNUNET_SOCIAL_ego_get_pub_key (const struct GNUNET_SOCIAL_Ego *ego) -{ - return &ego->pub_key; -} - - -/** - * Get the hash of the public key of @a ego. - * - * @param ego - * Ego. - * - * @return Hash of the public key of @a ego. - */ -const struct GNUNET_HashCode * -GNUNET_SOCIAL_ego_get_pub_key_hash (const struct GNUNET_SOCIAL_Ego *ego) -{ - return &ego->pub_key_hash; -} - - -/** - * Get the name of @a ego. - * - * @param ego - * Ego. - * - * @return Public key of @a ego. - */ -const char * -GNUNET_SOCIAL_ego_get_name (const struct GNUNET_SOCIAL_Ego *ego) -{ - return ego->name; -} - - -/** - * Get the public key of @a nym. - * - * Suitable, for example, to be used with GNUNET_SOCIAL_zone_add_nym(). - * - * @param nym - * Pseudonym. - * - * @return Public key of @a nym. - */ -const struct GNUNET_CRYPTO_EcdsaPublicKey * -GNUNET_SOCIAL_nym_get_pub_key (const struct GNUNET_SOCIAL_Nym *nym) -{ - return &nym->pub_key; -} - - -/** - * Get the hash of the public key of @a nym. - * - * @param nym - * Pseudonym. - * - * @return Hash of the public key of @a nym. - */ -const struct GNUNET_HashCode * -GNUNET_SOCIAL_nym_get_pub_key_hash (const struct GNUNET_SOCIAL_Nym *nym) -{ - return &nym->pub_key_hash; -} - - -/** - * Send a message to all nyms that are present in the place. - * - * This function is restricted to the host. Nyms can only send requests - * to the host who can decide to relay it to everyone in the place. - * - * @param host Host of the place. - * @param method_name Method to use for the announcement. - * @param env Environment containing variables for the message and operations - * on objects of the place. Can be NULL. - * @param notify Function to call to get the payload of the announcement. - * @param notify_cls Closure for @a notify. - * @param flags Flags for this announcement. - * - * @return NULL on error (announcement already in progress?). - */ -struct GNUNET_SOCIAL_Announcement * -GNUNET_SOCIAL_host_announce (struct GNUNET_SOCIAL_Host *hst, - const char *method_name, - const struct GNUNET_PSYC_Environment *env, - GNUNET_PSYC_TransmitNotifyData notify_data, - void *notify_data_cls, - enum GNUNET_SOCIAL_AnnounceFlags flags) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "PSYC_transmit_message for host, method: %s\n", - method_name); - if (GNUNET_OK == - GNUNET_PSYC_transmit_message (hst->plc.tmit, method_name, env, - NULL, notify_data, notify_data_cls, flags)) - return (struct GNUNET_SOCIAL_Announcement *) hst->plc.tmit; - else - return NULL; -} - - -/** - * Resume transmitting announcement. - * - * @param a - * The announcement to resume. - */ -void -GNUNET_SOCIAL_host_announce_resume (struct GNUNET_SOCIAL_Announcement *a) -{ - GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) a); -} - - -/** - * Cancel announcement. - * - * @param a - * The announcement to cancel. - */ -void -GNUNET_SOCIAL_host_announce_cancel (struct GNUNET_SOCIAL_Announcement *a) -{ - GNUNET_PSYC_transmit_cancel ((struct GNUNET_PSYC_TransmitHandle *) a); -} - - -/** - * Obtain handle for a hosted place. - * - * The returned handle can be used to access the place API. - * - * @param host Handle for the host. - * - * @return Handle for the hosted place, valid as long as @a host is valid. - */ -struct GNUNET_SOCIAL_Place * -GNUNET_SOCIAL_host_get_place (struct GNUNET_SOCIAL_Host *hst) -{ - return &hst->plc; -} - - -/** - * Disconnect from a home. - * - * Invalidates host handle. - * - * @param hst - * The host to disconnect. - */ -void -GNUNET_SOCIAL_host_disconnect (struct GNUNET_SOCIAL_Host *hst, - GNUNET_ContinuationCallback disconnect_cb, - void *cls) -{ - struct GNUNET_SOCIAL_Place *plc = &hst->plc; - - plc->disconnect_cb = disconnect_cb; - plc->disconnect_cls = cls; - place_disconnect (plc); -} - - -/** - * Stop hosting the home. - * - * Sends a _notice_place_closing announcement to the home. - * Invalidates host handle. - * - * @param hst - * The host leaving. - * @param env - * Environment for the message or NULL. - * _nym is set to @e nym regardless whether an @e env is provided. - * @param disconnect_cb - * Function called after the host left the place - * and disconnected from the social service. - * @param cls - * Closure for @a disconnect_cb. - */ -void -GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *hst, - const struct GNUNET_PSYC_Environment *env, - GNUNET_ContinuationCallback disconnect_cb, - void *cls) -{ - struct GNUNET_MQ_Envelope *envelope; - - GNUNET_SOCIAL_host_announce (hst, "_notice_place_closing", env, NULL, NULL, - GNUNET_SOCIAL_ANNOUNCE_NONE); - hst->plc.disconnect_cb = disconnect_cb; - hst->plc.disconnect_cls = cls; - envelope = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE); - GNUNET_MQ_send (hst->plc.mq, - envelope); -} - - -/*** GUEST ***/ - - -static void -guest_connect (struct GNUNET_SOCIAL_Guest *gst); - - -static void -guest_reconnect (void *cls) -{ - guest_connect (cls); -} - - -/** - * Guest client disconnected from service. - * - * Reconnect after backoff period. - */ -static void -guest_disconnected (void *cls, enum GNUNET_MQ_Error error) -{ - struct GNUNET_SOCIAL_Guest *gst = cls; - struct GNUNET_SOCIAL_Place *plc = &gst->plc; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Guest client disconnected (%d), re-connecting\n", - (int) error); - if (NULL != plc->tmit) - { - GNUNET_PSYC_transmit_destroy (plc->tmit); - plc->tmit = NULL; - } - if (NULL != plc->mq) - { - GNUNET_MQ_destroy (plc->mq); - plc->mq = NULL; - } - - plc->reconnect_task = GNUNET_SCHEDULER_add_delayed (plc->reconnect_delay, - guest_reconnect, - gst); - plc->reconnect_delay = GNUNET_TIME_STD_BACKOFF (plc->reconnect_delay); -} - - -static void -guest_connect (struct GNUNET_SOCIAL_Guest *gst) -{ - struct GNUNET_SOCIAL_Place *plc = &gst->plc; - - struct GNUNET_MQ_MessageHandler handlers[] = { - GNUNET_MQ_hd_fixed_size (guest_enter_ack, - GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK, - struct GNUNET_PSYC_CountersResultMessage, - gst), - GNUNET_MQ_hd_fixed_size (place_leave_ack, - GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE_ACK, - struct GNUNET_MessageHeader, - plc), - GNUNET_MQ_hd_var_size (guest_enter_decision, - GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION, - struct GNUNET_PSYC_JoinDecisionMessage, - gst), - GNUNET_MQ_hd_var_size (place_message, - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, - struct GNUNET_PSYC_MessageHeader, - plc), - GNUNET_MQ_hd_fixed_size (place_message_ack, - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK, - struct GNUNET_MessageHeader, - plc), - GNUNET_MQ_hd_var_size (place_history_result, - GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT, - struct GNUNET_OperationResultMessage, - plc), - GNUNET_MQ_hd_var_size (place_state_result, - GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT, - struct GNUNET_OperationResultMessage, - plc), - GNUNET_MQ_hd_var_size (place_result, - GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE, - struct GNUNET_OperationResultMessage, - plc), - GNUNET_MQ_handler_end () - }; - - plc->mq = GNUNET_CLIENT_connect (plc->cfg, "social", - handlers, guest_disconnected, gst); - GNUNET_assert (NULL != plc->mq); - plc->tmit = GNUNET_PSYC_transmit_create (plc->mq); - - GNUNET_MQ_send_copy (plc->mq, plc->connect_env); -} - - -static struct GNUNET_MQ_Envelope * -guest_enter_request_create (const char *app_id, - const struct GNUNET_CRYPTO_EcdsaPublicKey *ego_pub_key, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, - const struct GNUNET_PeerIdentity *origin, - size_t relay_count, - const struct GNUNET_PeerIdentity *relays, - const struct GNUNET_PSYC_Message *join_msg) -{ - uint16_t app_id_size = strlen (app_id) + 1; - uint16_t join_msg_size = ntohs (join_msg->header.size); - uint16_t relay_size = relay_count * sizeof (*relays); - - struct GuestEnterRequest *greq; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (greq, app_id_size + relay_size + join_msg_size, - GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER); - greq->place_pub_key = *place_pub_key; - greq->ego_pub_key = *ego_pub_key; - greq->origin = *origin; - greq->relay_count = htonl (relay_count); - - char *p = (char *) &greq[1]; - GNUNET_memcpy (p, app_id, app_id_size); - p += app_id_size; - - if (0 < relay_size) - { - GNUNET_memcpy (p, relays, relay_size); - p += relay_size; - } - - GNUNET_memcpy (p, join_msg, join_msg_size); - return env; -} - - -/** - * Request entry to a place as a guest. - * - * @param app - * Application handle. - * @param ego - * Identity of the guest. - * @param place_pub_key - * Public key of the place to enter. - * @param flags - * Flags for the entry. - * @param origin - * Peer identity of the origin of the underlying multicast group. - * @param relay_count - * Number of elements in the @a relays array. - * @param relays - * Relays for the underlying multicast group. - * @param method_name - * Method name for the message. - * @param env - * Environment containing variables for the message, or NULL. - * @param data - * Payload for the message to give to the enter callback. - * @param data_size - * Number of bytes in @a data. - * @param slicer - * Slicer to use for processing incoming requests from guests. - * - * @return NULL on errors, otherwise handle for the guest. - */ -struct GNUNET_SOCIAL_Guest * -GNUNET_SOCIAL_guest_enter (const struct GNUNET_SOCIAL_App *app, - const struct GNUNET_SOCIAL_Ego *ego, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, - enum GNUNET_PSYC_SlaveJoinFlags flags, - const struct GNUNET_PeerIdentity *origin, - uint32_t relay_count, - const struct GNUNET_PeerIdentity *relays, - const struct GNUNET_PSYC_Message *entry_msg, - struct GNUNET_PSYC_Slicer *slicer, - GNUNET_SOCIAL_GuestEnterCallback local_enter_cb, - GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb, - void *cls) -{ - struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst)); - struct GNUNET_SOCIAL_Place *plc = &gst->plc; - - plc->ego_pub_key = ego->pub_key; - plc->pub_key = *place_pub_key; - plc->cfg = app->cfg; - plc->is_host = GNUNET_NO; - plc->slicer = slicer; - - plc->op = GNUNET_OP_create (); - - plc->connect_env - = guest_enter_request_create (app->id, &ego->pub_key, &plc->pub_key, - origin, relay_count, relays, entry_msg); - - gst->enter_cb = local_enter_cb; - gst->entry_dcsn_cb = entry_dcsn_cb; - gst->cb_cls = cls; - - guest_connect (gst); - return gst; -} - - -/** - * Request entry to a place by name as a guest. - * - * @param app - * Application handle. - * @param ego - * Identity of the guest. - * @param gns_name - * GNS name of the place to enter. Either in the form of - * 'room.friend.gnu', or 'NYMPUBKEY.zkey'. This latter case refers to - * the 'PLACE' record of the empty label ("+") in the GNS zone with the - * nym's public key 'NYMPUBKEY', and can be used to request entry to a - * pseudonym's place directly. - * @param password - * Password to decrypt the record, or NULL for cleartext records. - * @param join_msg - * Entry request message or NULL. - * @param slicer - * Slicer to use for processing incoming requests from guests. - * @param local_enter_cb - * Called upon connection established to the social service. - * @param entry_decision_cb - * Called upon receiving entry decision. - * - * @return NULL on errors, otherwise handle for the guest. - */ -struct GNUNET_SOCIAL_Guest * -GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_SOCIAL_App *app, - const struct GNUNET_SOCIAL_Ego *ego, - const char *gns_name, - const char *password, - const struct GNUNET_PSYC_Message *join_msg, - struct GNUNET_PSYC_Slicer *slicer, - GNUNET_SOCIAL_GuestEnterCallback local_enter_cb, - GNUNET_SOCIAL_EntryDecisionCallback entry_decision_cb, - void *cls) -{ - struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst)); - struct GNUNET_SOCIAL_Place *plc = &gst->plc; - - if (NULL == password) - password = ""; - - uint16_t app_id_size = strlen (app->id) + 1; - uint16_t gns_name_size = strlen (gns_name) + 1; - uint16_t password_size = strlen (password) + 1; - - uint16_t join_msg_size = 0; - if (NULL != join_msg) - join_msg_size = ntohs (join_msg->header.size); - - struct GuestEnterByNameRequest *greq; - plc->connect_env - = GNUNET_MQ_msg_extra (greq, app_id_size + gns_name_size - + password_size + join_msg_size, - GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME); - - greq->ego_pub_key = ego->pub_key; - - char *p = (char *) &greq[1]; - GNUNET_memcpy (p, app->id, app_id_size); - p += app_id_size; - GNUNET_memcpy (p, gns_name, gns_name_size); - p += gns_name_size; - GNUNET_memcpy (p, password, password_size); - p += password_size; - if (NULL != join_msg) - GNUNET_memcpy (p, join_msg, join_msg_size); - - plc->ego_pub_key = ego->pub_key; - plc->cfg = app->cfg; - plc->is_host = GNUNET_NO; - plc->slicer = slicer; - - plc->op = GNUNET_OP_create (); - - gst->enter_cb = local_enter_cb; - gst->entry_dcsn_cb = entry_decision_cb; - gst->cb_cls = cls; - - guest_connect (gst); - return gst; -} - - -struct ReconnectContext -{ - struct GNUNET_SOCIAL_Guest *guest; - int *result; - int64_t *max_message_id; - GNUNET_SOCIAL_GuestEnterCallback enter_cb; - void *enter_cls; -}; - - -static void -guest_enter_reconnect_cb (void *cls, - int result, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, - uint64_t max_message_id) -{ - struct ReconnectContext *reconnect_ctx = cls; - - GNUNET_assert (NULL != reconnect_ctx); - reconnect_ctx->result = GNUNET_new (int); - *(reconnect_ctx->result) = result; - reconnect_ctx->max_message_id = GNUNET_new (int64_t); - *(reconnect_ctx->max_message_id) = max_message_id; -} - - -static void -guest_entry_dcsn_reconnect_cb (void *cls, - int is_admitted, - const struct GNUNET_PSYC_Message *entry_resp) -{ - struct ReconnectContext *reconnect_ctx = cls; - struct GNUNET_SOCIAL_Guest *gst = reconnect_ctx->guest; - - GNUNET_assert (NULL != reconnect_ctx); - GNUNET_assert (NULL != reconnect_ctx->result); - GNUNET_assert (NULL != reconnect_ctx->max_message_id); - if (GNUNET_YES != is_admitted) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Guest was rejected after calling " - "GNUNET_SOCIAL_guest_enter_reconnect ()\n"); - } - else if (NULL != reconnect_ctx->enter_cb) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "guest reconnected!\n"); - reconnect_ctx->enter_cb (reconnect_ctx->enter_cls, - *(reconnect_ctx->result), - &gst->plc.pub_key, - *(reconnect_ctx->max_message_id)); - } - GNUNET_free (reconnect_ctx->result); - GNUNET_free (reconnect_ctx->max_message_id); - GNUNET_free (reconnect_ctx); -} - - -/** - * Reconnect to an already entered place as guest. - * - * @param gconn - * Guest connection handle. - * @see GNUNET_SOCIAL_app_connect() & GNUNET_SOCIAL_AppGuestPlaceCallback() - * @param flags - * Flags for the entry. - * @param slicer - * Slicer to use for processing incoming requests from guests. - * @param enter_cb - * Called upon re-entering is complete. - * @param entry_decision_cb - * Called upon receiving entry decision. - * - * @return NULL on errors, otherwise handle for the guest. - */ -struct GNUNET_SOCIAL_Guest * -GNUNET_SOCIAL_guest_enter_reconnect (struct GNUNET_SOCIAL_GuestConnection *gconn, - enum GNUNET_PSYC_SlaveJoinFlags flags, - struct GNUNET_PSYC_Slicer *slicer, - GNUNET_SOCIAL_GuestEnterCallback enter_cb, - void *cls) -{ - struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst)); - struct GNUNET_SOCIAL_Place *plc = &gst->plc; - struct ReconnectContext *reconnect_ctx; - - uint16_t app_id_size = strlen (gconn->app->id) + 1; - struct GuestEnterRequest *greq; - plc->connect_env - = GNUNET_MQ_msg_extra (greq, app_id_size, - GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER); - greq->ego_pub_key = gconn->plc_msg.ego_pub_key; - greq->place_pub_key = gconn->plc_msg.place_pub_key; - greq->flags = htonl (flags); - - GNUNET_memcpy (&greq[1], gconn->app->id, app_id_size); - - plc->cfg = gconn->app->cfg; - plc->is_host = GNUNET_NO; - plc->slicer = slicer; - plc->pub_key = gconn->plc_msg.place_pub_key; - plc->ego_pub_key = gconn->plc_msg.ego_pub_key; - - reconnect_ctx = GNUNET_new (struct ReconnectContext); - reconnect_ctx->guest = gst; - reconnect_ctx->enter_cb = enter_cb; - reconnect_ctx->enter_cls = cls; - - plc->op = GNUNET_OP_create (); - gst->enter_cb = &guest_enter_reconnect_cb; - gst->entry_dcsn_cb = &guest_entry_dcsn_reconnect_cb; - gst->cb_cls = reconnect_ctx; - - guest_connect (gst); - return gst; -} - - -/** - * Talk to the host of the place. - * - * @param place - * Place where we want to talk to the host. - * @param method_name - * Method to invoke on the host. - * @param env - * Environment containing variables for the message, or NULL. - * @param notify_data - * Function to use to get the payload for the method. - * @param notify_data_cls - * Closure for @a notify_data. - * @param flags - * Flags for the message being sent. - * - * @return NULL if we are already trying to talk to the host, - * otherwise handle to cancel the request. - */ -struct GNUNET_SOCIAL_TalkRequest * -GNUNET_SOCIAL_guest_talk (struct GNUNET_SOCIAL_Guest *gst, - const char *method_name, - const struct GNUNET_PSYC_Environment *env, - GNUNET_PSYC_TransmitNotifyData notify_data, - void *notify_data_cls, - enum GNUNET_SOCIAL_TalkFlags flags) -{ - struct GNUNET_SOCIAL_Place *plc = &gst->plc; - GNUNET_assert (NULL != plc->tmit); - - if (GNUNET_OK == - GNUNET_PSYC_transmit_message (plc->tmit, method_name, env, - NULL, notify_data, notify_data_cls, flags)) - return (struct GNUNET_SOCIAL_TalkRequest *) plc->tmit; - else - return NULL; -} - - -/** - * Resume talking to the host of the place. - * - * @param tr - * Talk request to resume. - */ -void -GNUNET_SOCIAL_guest_talk_resume (struct GNUNET_SOCIAL_TalkRequest *tr) -{ - GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) tr); -} - - -/** - * Cancel talking to the host of the place. - * - * @param tr - * Talk request to cancel. - */ -void -GNUNET_SOCIAL_guest_talk_cancel (struct GNUNET_SOCIAL_TalkRequest *tr) -{ - GNUNET_PSYC_transmit_cancel ( (struct GNUNET_PSYC_TransmitHandle *) tr); -} - - -/** - * Disconnect from a place. - * - * Invalidates guest handle. - * - * @param gst - * The guest to disconnect. - */ -void -GNUNET_SOCIAL_guest_disconnect (struct GNUNET_SOCIAL_Guest *gst, - GNUNET_ContinuationCallback disconnect_cb, - void *cls) -{ - struct GNUNET_SOCIAL_Place *plc = &gst->plc; - - plc->disconnect_cb = disconnect_cb; - plc->disconnect_cls = cls; - place_disconnect (plc); -} - - -/** - * Leave a place temporarily or permanently. - * - * Notifies the owner of the place about leaving, and destroys the place handle. - * - * @param place - * Place to leave. - * @param keep_active - * Keep place active after last application disconnected. - * #GNUNET_YES or #GNUNET_NO - * @param env - * Optional environment for the leave message if @a keep_active - * is #GNUNET_NO. NULL if not needed. - * @param leave_cb - * Called upon disconnecting from the social service. - */ -void -GNUNET_SOCIAL_guest_leave (struct GNUNET_SOCIAL_Guest *gst, - struct GNUNET_PSYC_Environment *env, - GNUNET_ContinuationCallback disconnect_cb, - void *cls) -{ - struct GNUNET_MQ_Envelope *envelope; - - GNUNET_SOCIAL_guest_talk (gst, "_notice_place_leave", env, NULL, NULL, - GNUNET_SOCIAL_TALK_NONE); - gst->plc.disconnect_cb = disconnect_cb; - gst->plc.disconnect_cls = cls; - envelope = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE); - GNUNET_MQ_send (gst->plc.mq, - envelope); -} - - -/** - * Obtain handle for a place entered as guest. - * - * The returned handle can be used to access the place API. - * - * @param guest Handle for the guest. - * - * @return Handle for the place, valid as long as @a guest is valid. - */ -struct GNUNET_SOCIAL_Place * -GNUNET_SOCIAL_guest_get_place (struct GNUNET_SOCIAL_Guest *gst) -{ - return &gst->plc; -} - - -/** - * Obtain the public key of a place. - * - * @param plc - * Place. - * - * @return Public key of the place. - */ -const struct GNUNET_CRYPTO_EddsaPublicKey * -GNUNET_SOCIAL_place_get_pub_key (const struct GNUNET_SOCIAL_Place *plc) -{ - return &plc->pub_key; -} - - -/** - * Set message processing @a flags for a @a method_prefix. - * - * @param plc - * Place. - * @param method_prefix - * Method prefix @a flags apply to. - * @param flags - * The flags that apply to a matching @a method_prefix. - */ -void -GNUNET_SOCIAL_place_msg_proc_set (struct GNUNET_SOCIAL_Place *plc, - const char *method_prefix, - enum GNUNET_SOCIAL_MsgProcFlags flags) -{ - GNUNET_assert (NULL != method_prefix); - struct MsgProcRequest *mpreq; - uint16_t method_size = strnlen (method_prefix, - GNUNET_MAX_MESSAGE_SIZE - - sizeof (*mpreq)) + 1; - GNUNET_assert ('\0' == method_prefix[method_size - 1]); - - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (mpreq, method_size, - GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_SET); - mpreq->flags = htonl (flags); - GNUNET_memcpy (&mpreq[1], method_prefix, method_size); - - GNUNET_MQ_send (plc->mq, env); -} - - -/** - * Clear all message processing flags previously set for this place. - */ -void -GNUNET_SOCIAL_place_msg_proc_clear (struct GNUNET_SOCIAL_Place *plc) -{ - struct GNUNET_MessageHeader *req; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_CLEAR); - - GNUNET_MQ_send (plc->mq, env); -} - - -static struct GNUNET_SOCIAL_HistoryRequest * -place_history_replay (struct GNUNET_SOCIAL_Place *plc, - uint64_t start_message_id, - uint64_t end_message_id, - uint64_t message_limit, - const char *method_prefix, - uint32_t flags, - struct GNUNET_PSYC_Slicer *slicer, - GNUNET_ResultCallback result_cb, - void *cls) -{ - struct GNUNET_PSYC_HistoryRequestMessage *req; - struct GNUNET_SOCIAL_HistoryRequest *hist = GNUNET_malloc (sizeof (*hist)); - hist->plc = plc; - hist->slicer = slicer; - hist->result_cb = result_cb; - hist->cls = cls; - hist->op_id = GNUNET_OP_add (plc->op, op_recv_history_result, hist, NULL); - - GNUNET_assert (NULL != method_prefix); - uint16_t method_size = strnlen (method_prefix, - GNUNET_MAX_MESSAGE_SIZE - - sizeof (*req)) + 1; - GNUNET_assert ('\0' == method_prefix[method_size - 1]); - - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (req, method_size, - GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY); - req->start_message_id = GNUNET_htonll (start_message_id); - req->end_message_id = GNUNET_htonll (end_message_id); - req->message_limit = GNUNET_htonll (message_limit); - req->flags = htonl (flags); - req->op_id = GNUNET_htonll (hist->op_id); - GNUNET_memcpy (&req[1], method_prefix, method_size); - - GNUNET_MQ_send (plc->mq, env); - return hist; -} - - -/** - * Learn about the history of a place. - * - * Messages are returned through the @a slicer function - * and have the #GNUNET_PSYC_MESSAGE_HISTORIC flag set. - * - * @param place - * Place we want to learn more about. - * @param start_message_id - * First historic message we are interested in. - * @param end_message_id - * Last historic message we are interested in (inclusive). - * @param method_prefix - * Only retrieve messages with this method prefix. - * @param flags - * OR'ed GNUNET_PSYC_HistoryReplayFlags - * @param slicer - * Slicer to use for retrieved messages. - * Can be the same as the slicer of the place. - * @param result_cb - * Function called after all messages retrieved. - * NULL if not needed. - * @param cls Closure for @a result_cb. - */ -struct GNUNET_SOCIAL_HistoryRequest * -GNUNET_SOCIAL_place_history_replay (struct GNUNET_SOCIAL_Place *plc, - uint64_t start_message_id, - uint64_t end_message_id, - const char *method_prefix, - uint32_t flags, - struct GNUNET_PSYC_Slicer *slicer, - GNUNET_ResultCallback result_cb, - void *cls) -{ - return place_history_replay (plc, start_message_id, end_message_id, 0, - method_prefix, flags, slicer, result_cb, cls); -} - - -/** - * Learn about the history of a place. - * - * Sends messages through the slicer function of the place where - * start_message_id <= message_id <= end_message_id. - * The messages will have the #GNUNET_PSYC_MESSAGE_HISTORIC flag set. - * - * To get the latest message, use 0 for both the start and end message ID. - * - * @param place - * Place we want to learn more about. - * @param message_limit - * Maximum number of historic messages we are interested in. - * @param method_prefix - * Only retrieve messages with this method prefix. - * @param flags - * OR'ed GNUNET_PSYC_HistoryReplayFlags - * @param result_cb - * Function called after all messages retrieved. - * NULL if not needed. - * @param cls Closure for @a result_cb. - */ -struct GNUNET_SOCIAL_HistoryRequest * -GNUNET_SOCIAL_place_history_replay_latest (struct GNUNET_SOCIAL_Place *plc, - uint64_t message_limit, - const char *method_prefix, - uint32_t flags, - struct GNUNET_PSYC_Slicer *slicer, - GNUNET_ResultCallback result_cb, - void *cls) -{ - return place_history_replay (plc, 0, 0, message_limit, method_prefix, flags, - slicer, result_cb, cls); -} - - -/** - * Cancel learning about the history of a place. - * - * @param hist - * History lesson to cancel. - */ -void -GNUNET_SOCIAL_place_history_replay_cancel (struct GNUNET_SOCIAL_HistoryRequest *hist) -{ - GNUNET_OP_remove (hist->plc->op, hist->op_id); - GNUNET_free (hist); -} - - -/** - * Request matching state variables. - */ -static struct GNUNET_SOCIAL_LookHandle * -place_state_get (struct GNUNET_SOCIAL_Place *plc, - uint16_t type, const char *name, - GNUNET_PSYC_StateVarCallback var_cb, - GNUNET_ResultCallback result_cb, void *cls) -{ - struct GNUNET_PSYC_StateRequestMessage *req; - struct GNUNET_SOCIAL_LookHandle *look = GNUNET_malloc (sizeof (*look)); - look->plc = plc; - look->var_cb = var_cb; - look->result_cb = result_cb; - look->cls = cls; - look->op_id = GNUNET_OP_add (plc->op, &op_recv_state_result, look, NULL); - - GNUNET_assert (NULL != name); - size_t name_size = strnlen (name, GNUNET_MAX_MESSAGE_SIZE - - sizeof (*req)) + 1; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (req, name_size, type); - req->op_id = GNUNET_htonll (look->op_id); - GNUNET_memcpy (&req[1], name, name_size); - - GNUNET_MQ_send (plc->mq, env); - return look; -} - - -/** - * Look at a particular object in the place. - * - * The best matching object is returned (its name might be less specific than - * what was requested). - * - * @param place - * The place where to look. - * @param full_name - * Full name of the object. - * @param value_size - * Set to the size of the returned value. - * - * @return NULL if there is no such object at this place. - */ -struct GNUNET_SOCIAL_LookHandle * -GNUNET_SOCIAL_place_look_at (struct GNUNET_SOCIAL_Place *plc, - const char *full_name, - GNUNET_PSYC_StateVarCallback var_cb, - GNUNET_ResultCallback result_cb, - void *cls) -{ - return place_state_get (plc, GNUNET_MESSAGE_TYPE_PSYC_STATE_GET, - full_name, var_cb, result_cb, cls); -} - - -/** - * Look for objects in the place with a matching name prefix. - * - * @param place - * The place where to look. - * @param name_prefix - * Look at objects with names beginning with this value. - * @param var_cb - * Function to call for each object found. - * @param cls - * Closure for callback function. - * - * @return Handle that can be used to stop looking at objects. - */ -struct GNUNET_SOCIAL_LookHandle * -GNUNET_SOCIAL_place_look_for (struct GNUNET_SOCIAL_Place *plc, - const char *name_prefix, - GNUNET_PSYC_StateVarCallback var_cb, - GNUNET_ResultCallback result_cb, - void *cls) -{ - return place_state_get (plc, GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX, - name_prefix, var_cb, result_cb, cls); -} - - -/** - * Cancel a state request operation. - * - * @param sr - * Handle for the operation to cancel. - */ -void -GNUNET_SOCIAL_place_look_cancel (struct GNUNET_SOCIAL_LookHandle *look) -{ - GNUNET_OP_remove (look->plc->op, look->op_id); - GNUNET_free (look); -} - - -static void -op_recv_zone_add_place_result (void *cls, int64_t result, - const void *err_msg, uint16_t err_msg_size) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received zone add place result: %" PRId64 ".\n", result); - - struct ZoneAddPlaceHandle *add_plc = cls; - if (NULL != add_plc->result_cb) - add_plc->result_cb (add_plc->result_cls, result, err_msg, err_msg_size); - - GNUNET_free (add_plc); -} - - -/** - * Advertise @e place in the GNS zone of @e ego. - * - * @param app - * Application handle. - * @param ego - * Ego. - * @param place_pub_key - * Public key of place to add. - * @param name - * The name for the PLACE record to put in the zone. - * @param password - * Password used to encrypt the record or NULL to keep it cleartext. - * @param relay_count - * Number of elements in the @a relays array. - * @param relays - * List of relays to put in the PLACE record to advertise - * as entry points to the place in addition to the origin. - * @param expiration_time - * Expiration time of the record, use 0 to remove the record. - * @param result_cb - * Function called with the result of the operation. - * @param result_cls - * Closure for @a result_cb - * - * @return #GNUNET_OK if the request was sent, - * #GNUNET_SYSERR on error, e.g. the name/password is too long. - */ -int -GNUNET_SOCIAL_zone_add_place (const struct GNUNET_SOCIAL_App *app, - const struct GNUNET_SOCIAL_Ego *ego, - const char *name, - const char *password, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, - const struct GNUNET_PeerIdentity *origin, - uint32_t relay_count, - const struct GNUNET_PeerIdentity *relays, - struct GNUNET_TIME_Absolute expiration_time, - GNUNET_ResultCallback result_cb, - void *result_cls) -{ - struct ZoneAddPlaceRequest *preq; - size_t name_size = strlen (name) + 1; - size_t password_size = strlen (password) + 1; - size_t relay_size = relay_count * sizeof (*relays); - size_t payload_size = name_size + password_size + relay_size; - - if (GNUNET_MAX_MESSAGE_SIZE < sizeof (*preq) + payload_size) - return GNUNET_SYSERR; - - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (preq, payload_size, - GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_PLACE); - preq->expiration_time = GNUNET_htonll (expiration_time.abs_value_us); - preq->ego_pub_key = ego->pub_key; - preq->place_pub_key = *place_pub_key; - preq->origin = *origin; - preq->relay_count = htonl (relay_count); - - char *p = (char *) &preq[1]; - GNUNET_memcpy (p, name, name_size); - p += name_size; - GNUNET_memcpy (p, password, password_size); - p += password_size; - GNUNET_memcpy (p, relays, relay_size); - - struct ZoneAddPlaceHandle * add_plc = GNUNET_malloc (sizeof (*add_plc)); - add_plc->result_cb = result_cb; - add_plc->result_cls = result_cls; - - preq->op_id = GNUNET_htonll (GNUNET_OP_add (app->op, - op_recv_zone_add_place_result, - add_plc, NULL)); - - GNUNET_MQ_send (app->mq, env); - return GNUNET_OK; -} - - -static void -op_recv_zone_add_nym_result (void *cls, int64_t result, - const void *err_msg, uint16_t err_msg_size) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received zone add nym result: %" PRId64 ".\n", result); - - struct ZoneAddNymHandle *add_nym = cls; - if (NULL != add_nym->result_cb) - add_nym->result_cb (add_nym->result_cls, result, err_msg, err_msg_size); - - GNUNET_free (add_nym); -} - - -/** - * Add nym to the GNS zone of @e ego. - * - * @param cfg - * Configuration. - * @param ego - * Ego. - * @param name - * The name for the PKEY record to put in the zone. - * @param nym_pub_key - * Public key of nym to add. - * @param expiration_time - * Expiration time of the record, use 0 to remove the record. - * @param result_cb - * Function called with the result of the operation. - * @param result_cls - * Closure for @a result_cb - * - * @return #GNUNET_OK if the request was sent, - * #GNUNET_SYSERR on error, e.g. the name is too long. - */ -int -GNUNET_SOCIAL_zone_add_nym (const struct GNUNET_SOCIAL_App *app, - const struct GNUNET_SOCIAL_Ego *ego, - const char *name, - const struct GNUNET_CRYPTO_EcdsaPublicKey *nym_pub_key, - struct GNUNET_TIME_Absolute expiration_time, - GNUNET_ResultCallback result_cb, - void *result_cls) -{ - struct ZoneAddNymRequest *nreq; - - size_t name_size = strlen (name) + 1; - if (GNUNET_MAX_MESSAGE_SIZE < sizeof (*nreq) + name_size) - return GNUNET_SYSERR; - - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg_extra (nreq, name_size, - GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_NYM); - nreq->expiration_time = GNUNET_htonll (expiration_time.abs_value_us); - nreq->ego_pub_key = ego->pub_key; - nreq->nym_pub_key = *nym_pub_key; - GNUNET_memcpy (&nreq[1], name, name_size); - - struct ZoneAddNymHandle *add_nym = GNUNET_malloc (sizeof (*add_nym)); - add_nym->result_cb = result_cb; - add_nym->result_cls = result_cls; - - nreq->op_id = GNUNET_htonll (GNUNET_OP_add (app->op, - op_recv_zone_add_nym_result, - add_nym, NULL)); - - GNUNET_MQ_send (app->mq, env); - return GNUNET_OK; -} - - -/*** APP ***/ - - -static void -app_connect (struct GNUNET_SOCIAL_App *app); - - -static void -app_reconnect (void *cls) -{ - app_connect (cls); -} - - -/** - * App client disconnected from service. - * - * Reconnect after backoff period. - */ -static void -app_disconnected (void *cls, enum GNUNET_MQ_Error error) -{ - struct GNUNET_SOCIAL_App *app = cls; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "App client disconnected (%d), re-connecting\n", - (int) error); - if (NULL != app->mq) - { - GNUNET_MQ_destroy (app->mq); - app->mq = NULL; - } - - app->reconnect_task = GNUNET_SCHEDULER_add_delayed (app->reconnect_delay, - app_reconnect, - app); - app->reconnect_delay = GNUNET_TIME_STD_BACKOFF (app->reconnect_delay); -} - - -static void -app_connect (struct GNUNET_SOCIAL_App *app) -{ - struct GNUNET_MQ_MessageHandler handlers[] = { - GNUNET_MQ_hd_var_size (app_ego, - GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO, - struct AppEgoMessage, - app), - GNUNET_MQ_hd_fixed_size (app_ego_end, - GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO_END, - struct GNUNET_MessageHeader, - app), - GNUNET_MQ_hd_var_size (app_place, - GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE, - struct AppPlaceMessage, - app), - GNUNET_MQ_hd_fixed_size (app_place_end, - GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE_END, - struct GNUNET_MessageHeader, - app), - GNUNET_MQ_hd_var_size (app_result, - GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE, - struct GNUNET_OperationResultMessage, - app), - GNUNET_MQ_handler_end () - }; - - app->mq = GNUNET_CLIENT_connect (app->cfg, "social", - handlers, app_disconnected, app); - GNUNET_assert (NULL != app->mq); - GNUNET_MQ_send_copy (app->mq, app->connect_env); -} - - -/** - * Connect application to the social service. - * - * The @host_place_cb and @guest_place_cb functions are - * initially called for each entered places, - * then later each time a new place is entered with the current application ID. - * - * @param cfg - * Configuration. - * @param id - * Application ID. - * @param ego_cb - * Function to notify about an available ego. - * @param host_cb - * Function to notify about a place entered as host. - * @param guest_cb - * Function to notify about a place entered as guest. - * @param cls - * Closure for the callbacks. - * - * @return Handle that can be used to stop listening. - */ -struct GNUNET_SOCIAL_App * -GNUNET_SOCIAL_app_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, - const char *id, - GNUNET_SOCIAL_AppEgoCallback ego_cb, - GNUNET_SOCIAL_AppHostPlaceCallback host_cb, - GNUNET_SOCIAL_AppGuestPlaceCallback guest_cb, - GNUNET_SOCIAL_AppConnectedCallback connected_cb, - void *cls) -{ - uint16_t app_id_size = strnlen (id, GNUNET_SOCIAL_APP_MAX_ID_SIZE); - if (GNUNET_SOCIAL_APP_MAX_ID_SIZE == app_id_size) - return NULL; - app_id_size++; - - struct GNUNET_SOCIAL_App *app = GNUNET_malloc (sizeof *app); - app->cfg = cfg; - app->ego_cb = ego_cb; - app->host_cb = host_cb; - app->guest_cb = guest_cb; - app->connected_cb = connected_cb; - app->cb_cls = cls; - app->egos = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - app->op = GNUNET_OP_create (); - app->id = GNUNET_malloc (app_id_size); - GNUNET_memcpy (app->id, id, app_id_size); - - struct AppConnectRequest *creq; - app->connect_env = GNUNET_MQ_msg_extra (creq, app_id_size, - GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT); - GNUNET_memcpy (&creq[1], app->id, app_id_size); - - app_connect (app); - return app; -} - - -static void -app_cleanup (struct GNUNET_SOCIAL_App *app) -{ - if (NULL != app->mq) - { - GNUNET_MQ_destroy (app->mq); - app->mq = NULL; - } - if (NULL != app->disconnect_cb) - { - app->disconnect_cb (app->disconnect_cls); - app->disconnect_cb = NULL; - } - GNUNET_free (app); -} - -/** - * Disconnect application. - * - * @param app - * Application handle. - * @param disconnect_cb - * Disconnect callback. - * @param disconnect_cls - * Disconnect closure. - */ -void -GNUNET_SOCIAL_app_disconnect (struct GNUNET_SOCIAL_App *app, - GNUNET_ContinuationCallback disconnect_cb, - void *disconnect_cls) -{ - if (NULL == app) return; - - app->disconnect_cb = disconnect_cb; - app->disconnect_cls = disconnect_cls; - - if (NULL != app->mq) - { - struct GNUNET_MQ_Envelope *env = GNUNET_MQ_get_last_envelope (app->mq); - if (NULL != env) - { - GNUNET_MQ_notify_sent (env, (GNUNET_SCHEDULER_TaskCallback) app_cleanup, app); - } - else - { - app_cleanup (app); - } - } - else - { - app_cleanup (app); - } -} - - -/** - * Detach application from a place. - * - * Removes the place from the entered places list for this application. - * Note: this does not disconnect from the place. - * - * @see GNUNET_SOCIAL_host_disconnect() and GNUNET_SOCIAL_guest_disconnect() - * - * @param app - * Application. - * @param plc - * Place. - */ -void -GNUNET_SOCIAL_app_detach (struct GNUNET_SOCIAL_App *app, - struct GNUNET_SOCIAL_Place *plc) -{ - struct AppDetachRequest *dreq; - struct GNUNET_MQ_Envelope * - env = GNUNET_MQ_msg (dreq, GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH); - dreq->place_pub_key = plc->pub_key; - dreq->ego_pub_key = plc->ego_pub_key; - - GNUNET_MQ_send (app->mq, env); -} - - -/* end of social_api.c */ diff --git a/src/social/test_social.c b/src/social/test_social.c deleted file mode 100644 index feac3c591..000000000 --- a/src/social/test_social.c +++ /dev/null @@ -1,1449 +0,0 @@ -/* - * This file is part of GNUnet - * Copyright (C) 2013 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * or (at your option) any later version. - * - * GNUnet is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - - SPDX-License-Identifier: AGPL3.0-or-later - */ -/** - * @file social/test_social.c - * @brief Tests for the Social API. - * @author Gabor X Toth - */ - -#include - -#include "platform.h" -#include "gnunet_crypto_lib.h" -#include "gnunet_common.h" -#include "gnunet_util_lib.h" -#include "gnunet_testing_lib.h" -#include "gnunet_psyc_util_lib.h" -#include "gnunet_social_service.h" -#include "gnunet_identity_service.h" - -#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) - -#define DATA2ARG(data) data, sizeof (data) - -/** - * Return value from 'main'. - */ -int res; - -struct GNUNET_SOCIAL_App *app; -const char *app_id = "test"; - -/** - * Handle for task for timeout termination. - */ -struct GNUNET_SCHEDULER_Task *end_badly_task; - -const struct GNUNET_CONFIGURATION_Handle *cfg; - -struct GNUNET_PeerIdentity this_peer; - -struct GNUNET_IDENTITY_Handle *id; - -const struct GNUNET_IDENTITY_Ego *identity_host_ego; -const struct GNUNET_IDENTITY_Ego *identity_guest_ego; - -const struct GNUNET_SOCIAL_Ego *host_ego; -const struct GNUNET_SOCIAL_Ego *guest_ego; - -const char *host_name = "Host One"; -const char *guest_name = "Guest One"; - -struct GNUNET_CRYPTO_EddsaPrivateKey *place_key; -struct GNUNET_CRYPTO_EcdsaPrivateKey *guest_key; - -struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; -struct GNUNET_HashCode place_pub_hash; - -const struct GNUNET_CRYPTO_EcdsaPublicKey *guest_pub_key; -const struct GNUNET_CRYPTO_EcdsaPublicKey *host_pub_key; - -struct GNUNET_PSYC_Slicer *host_slicer; -struct GNUNET_PSYC_Slicer *guest_slicer; - -struct GNUNET_SOCIAL_Host *hst; -struct GNUNET_SOCIAL_Guest *gst; - -struct GNUNET_SOCIAL_Place *hst_plc; -struct GNUNET_SOCIAL_Place *gst_plc; - -struct GNUNET_SOCIAL_Nym *nym_eject; - -struct GuestEnterMessage -{ - struct GNUNET_PSYC_Message *msg; - const char *method_name; - struct GNUNET_PSYC_Environment *env; - void *data; - uint16_t data_size; -} guest_enter_msg; - -struct TransmitClosure -{ - struct GNUNET_SOCIAL_Announcement *host_ann; - struct GNUNET_SOCIAL_TalkRequest *guest_talk; - struct GNUNET_PSYC_Environment *env; - char *data[16]; - uint8_t data_delay[16]; - uint8_t data_count; - uint8_t paused; - uint8_t n; -} tmit; - -struct ResultClosure { - uint32_t n; -} mod_foo_bar_rcls; - -uint8_t join_req_count; -struct GNUNET_PSYC_Message *join_resp; - -uint32_t counter; - -uint8_t is_guest_nym_added = GNUNET_NO; -uint8_t is_host_reconnected = GNUNET_NO; -uint8_t is_guest_reconnected = GNUNET_NO; - -enum -{ - TEST_NONE = 0, - TEST_IDENTITIES_CREATE = 1, - TEST_HOST_ENTER = 2, - TEST_GUEST_ENTER = 3, - TEST_HOST_ANSWER_DOOR_REFUSE = 4, - TEST_GUEST_RECV_ENTRY_DCSN_REFUSE = 5, - TEST_HOST_ANSWER_DOOR_ADMIT = 6, - TEST_GUEST_RECV_ENTRY_DCSN_ADMIT = 7, - TEST_HOST_ANNOUNCE = 8, - TEST_HOST_ANNOUNCE_END = 9, - TEST_GUEST_TALK = 10, - TEST_HOST_ANNOUNCE2 = 11, - TEST_HOST_ANNOUNCE2_END = 12, - TEST_GUEST_HISTORY_REPLAY = 13, - TEST_GUEST_HISTORY_REPLAY_LATEST = 14, - TEST_GUEST_LOOK_AT = 15, - TEST_GUEST_LOOK_FOR = 16, - TEST_GUEST_LEAVE = 17, - TEST_ZONE_ADD_PLACE = 18, - TEST_GUEST_ENTER_BY_NAME = 19, - TEST_RECONNECT = 20, - TEST_GUEST_LEAVE2 = 21, - TEST_HOST_LEAVE = 22, -} test; - - -static void -schedule_guest_leave (void *cls); - - -static void -host_answer_door (void *cls, - struct GNUNET_SOCIAL_Nym *nym, - const char *method_name, - struct GNUNET_PSYC_Environment *env, - const void *data, - size_t data_size); - -static void -host_enter (); - -static void -guest_init (); - -static void -guest_enter (); - -static void -guest_enter_by_name (); - -static void -guest_talk (); - -static void -host_announce2 (); - - -/** - * Terminate the test case (failure). - * - * @param cls NULL - */ -static void -end_badly (void *cls) -{ - end_badly_task = NULL; - GNUNET_SCHEDULER_shutdown (); - res = 2; - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Test FAILED.\n"); -} - - -/** - * Terminate the test case (failure). - * - * @param cls NULL - */ -static void -end_shutdown (void *cls) -{ - if (NULL != id) - { - GNUNET_IDENTITY_disconnect (id); - id = NULL; - } - - if (NULL != guest_slicer) - { - GNUNET_PSYC_slicer_destroy (guest_slicer); - guest_slicer = NULL; - } - - if (NULL != host_slicer) - { - GNUNET_PSYC_slicer_destroy (host_slicer); - host_slicer = NULL; - } - if (NULL != end_badly_task) - { - GNUNET_SCHEDULER_cancel (end_badly_task); - end_badly_task = NULL; - } - if (NULL != gst) - { - GNUNET_SOCIAL_guest_leave (gst, NULL, NULL, NULL); - gst = NULL; - gst_plc = NULL; - } - if (NULL != hst) - { - GNUNET_SOCIAL_host_leave (hst, NULL, NULL, NULL); - hst = NULL; - hst_plc = NULL; - } - GNUNET_SOCIAL_app_disconnect (app, NULL, NULL); -} - - -/** - * Terminate the test case (success). - * - * @param cls NULL - */ -static void -end_normally (void *cls) -{ - GNUNET_SCHEDULER_shutdown (); - res = 0; - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Test PASSED.\n"); -} - - -/** - * Finish the test case (successfully). - */ -static void -end () -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Ending tests.\n", test); - - if (end_badly_task != NULL) - { - GNUNET_SCHEDULER_cancel (end_badly_task); - end_badly_task = NULL; - } - GNUNET_SCHEDULER_add_now (&end_normally, NULL); -} - - -static void -transmit_resume (void *cls) -{ - struct TransmitClosure *tmit = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Transmission resumed.\n", test); - if (NULL != tmit->host_ann) - GNUNET_SOCIAL_host_announce_resume (tmit->host_ann); - else - GNUNET_SOCIAL_guest_talk_resume (tmit->guest_talk); -} - - -static int -notify_data (void *cls, uint16_t *data_size, void *data) -{ - struct TransmitClosure *tmit = cls; - if (NULL != tmit->env) - { - GNUNET_PSYC_env_destroy (tmit->env); - tmit->env = NULL; - } - if (0 == tmit->data_count) - { - *data_size = 0; - return GNUNET_YES; - } - - uint16_t size = strlen (tmit->data[tmit->n]); - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Transmit notify data: %u bytes available, " - "processing fragment %u/%u (size %u).\n", - test, *data_size, tmit->n + 1, tmit->data_count, size); - if (*data_size < size) - { - *data_size = 0; - GNUNET_assert (0); - return GNUNET_SYSERR; - } - - if (GNUNET_YES != tmit->paused && 0 < tmit->data_delay[tmit->n]) - { - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Transmission paused.\n", test); - tmit->paused = GNUNET_YES; - GNUNET_SCHEDULER_add_delayed ( - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, - tmit->data_delay[tmit->n]), - &transmit_resume, tmit); - *data_size = 0; - return GNUNET_NO; - } - tmit->paused = GNUNET_NO; - - *data_size = size; - GNUNET_memcpy (data, tmit->data[tmit->n], size); - - return ++tmit->n < tmit->data_count ? GNUNET_NO : GNUNET_YES; -} - - -static void -host_left () -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: The host has left the place.\n", test); - end (); -} - - -static void -schedule_host_leave (void *cls) -{ - test = TEST_HOST_LEAVE; - GNUNET_SOCIAL_host_leave (hst, NULL, &host_left, NULL); - hst = NULL; - hst_plc = NULL; -} - - -static void -host_farewell2 (void *cls, - const struct GNUNET_SOCIAL_Nym *nym, - struct GNUNET_PSYC_Environment *env) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Nym left the place again.\n"); - GNUNET_SCHEDULER_add_now (&schedule_host_leave, NULL); -} - - -static void -host_reconnected (void *cls, int result, - const struct GNUNET_CRYPTO_EddsaPublicKey *home_pub_key, - uint64_t max_message_id) -{ - place_pub_key = *home_pub_key; - GNUNET_CRYPTO_hash (&place_pub_key, sizeof (place_pub_key), &place_pub_hash); - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Host reconnected to place %s\n", - test, GNUNET_h2s (&place_pub_hash)); - - is_host_reconnected = GNUNET_YES; - if (GNUNET_YES == is_guest_reconnected) - { - GNUNET_assert (NULL != gst); - GNUNET_SCHEDULER_add_now (&schedule_guest_leave, NULL); - } -} - - -static void -guest_reconnected (void *cls, int result, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, - uint64_t max_message_id) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Guest reconnected to place: %d\n", - test, result); - GNUNET_assert (0 <= result); - - is_guest_reconnected = GNUNET_YES; - if (GNUNET_YES == is_host_reconnected) - { - GNUNET_assert (NULL != gst); - GNUNET_SCHEDULER_add_now (&schedule_guest_leave, NULL); - } -} - - -static void -app_connected (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: App connected: %p\n", test, cls); -} - - -static void -app_recv_host (void *cls, - struct GNUNET_SOCIAL_HostConnection *hconn, - struct GNUNET_SOCIAL_Ego *ego, - const struct GNUNET_CRYPTO_EddsaPublicKey *host_pub_key, - enum GNUNET_SOCIAL_AppPlaceState place_state) -{ - struct GNUNET_HashCode host_pub_hash; - - GNUNET_CRYPTO_hash (host_pub_key, - sizeof (*host_pub_key), - &host_pub_hash); - - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Got app host place notification: %s\n", - test, - GNUNET_h2s (&host_pub_hash)); - - if (test == TEST_RECONNECT) - { - if (0 == memcmp (&place_pub_key, host_pub_key, sizeof (*host_pub_key))) - { - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Reconnecting to host place: %s\n", - test, GNUNET_h2s (&host_pub_hash)); - hst = GNUNET_SOCIAL_host_enter_reconnect (hconn, host_slicer, - &host_reconnected, - &host_answer_door, - &host_farewell2, - NULL); - } - } -} - - -static void -app_recv_guest (void *cls, - struct GNUNET_SOCIAL_GuestConnection *gconn, - struct GNUNET_SOCIAL_Ego *ego, - const struct GNUNET_CRYPTO_EddsaPublicKey *guest_pub_key, - enum GNUNET_SOCIAL_AppPlaceState place_state) -{ - struct GNUNET_HashCode guest_pub_hash; - - GNUNET_CRYPTO_hash (guest_pub_key, - sizeof (*guest_pub_key), - &guest_pub_hash); - - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Got app guest place notification: %s\n", - test, GNUNET_h2s (&guest_pub_hash)); - - if (test == TEST_RECONNECT) - { - if (0 == memcmp (&place_pub_key, - guest_pub_key, - sizeof (*guest_pub_key))) - { - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Reconnecting to guest place: %s\n", - test, GNUNET_h2s (&guest_pub_hash)); - gst = GNUNET_SOCIAL_guest_enter_reconnect (gconn, - GNUNET_PSYC_SLAVE_JOIN_NONE, - guest_slicer, - &guest_reconnected, - NULL); - GNUNET_assert (NULL != gst); - } - } -} - - -static void -enter_if_ready () -{ - if (NULL == host_ego || NULL == guest_ego) - { - return; - } - host_enter (); - guest_init (); -} - - -static void -app_recv_ego (void *cls, - struct GNUNET_SOCIAL_Ego *ego, - const struct GNUNET_CRYPTO_EcdsaPublicKey *ego_pub_key, - const char *name) -{ - char *ego_pub_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (ego_pub_key); - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Got app ego notification: %p %s %s\n", - test, ego, name, ego_pub_str); - GNUNET_free (ego_pub_str); - - if (NULL != strstr (name, host_name)) - { - host_ego = ego; - host_pub_key = ego_pub_key; - if (TEST_IDENTITIES_CREATE == test) - { - enter_if_ready (); - } - else - { - GNUNET_assert (TEST_RECONNECT == test); - } - } - else if (NULL != strstr (name, guest_name)) - { - guest_ego = ego; - guest_pub_key = ego_pub_key; - if (TEST_IDENTITIES_CREATE == test) - { - enter_if_ready (); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "test = %d\n", - test); - GNUNET_assert (TEST_RECONNECT == test); - } - } -} - - -static void -schedule_reconnect (void *cls) -{ - test = TEST_RECONNECT; - GNUNET_SOCIAL_host_disconnect (hst, NULL, NULL); - GNUNET_SOCIAL_guest_disconnect (gst, NULL, NULL); - hst = NULL; - gst = NULL; - - GNUNET_SOCIAL_app_disconnect (app, NULL, NULL); - app = GNUNET_SOCIAL_app_connect (cfg, app_id, - &app_recv_ego, - &app_recv_host, - &app_recv_guest, - &app_connected, - NULL); -} - - -static void -host_recv_zone_add_place_result (void *cls, int64_t result, - const void *data, uint16_t data_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Zone add place result: %" PRId64 " (%.*s).\n", - test, result, data_size, (const char *) data); - GNUNET_assert (GNUNET_YES == result); - - GNUNET_assert (GNUNET_YES == is_guest_nym_added); - guest_enter_by_name (); -} - - -static void -zone_add_place () -{ - test = TEST_ZONE_ADD_PLACE; - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Adding place to zone.\n", test); - - GNUNET_SOCIAL_zone_add_place (app, host_ego, "home", "let.me*in!", - &place_pub_key, &this_peer, 1, &this_peer, - GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES), - host_recv_zone_add_place_result, app); -} - - -static void -host_farewell (void *cls, - const struct GNUNET_SOCIAL_Nym *nym, - struct GNUNET_PSYC_Environment *env) -{ - const struct GNUNET_CRYPTO_EcdsaPublicKey * - nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym); - - char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key); - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Farewell: nym %s (%s) has left the place.\n", - test, GNUNET_h2s (GNUNET_SOCIAL_nym_get_pub_key_hash (nym)), str); - GNUNET_free (str); - GNUNET_assert (1 == GNUNET_PSYC_env_get_count (env)); - if (0 != memcmp (guest_pub_key, nym_key, sizeof (*nym_key))) - { - str = GNUNET_CRYPTO_ecdsa_public_key_to_string (guest_pub_key); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Test #%u: Farewell: nym does not match guest: %s\n", - test, str); - GNUNET_free (str); - GNUNET_assert (0); - } - zone_add_place (); -} - - -static void -guest_left (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: The guest has left the place.\n", test); -} - - -static void -guest_leave () -{ - if (test < TEST_RECONNECT) - test = TEST_GUEST_LEAVE; - else - test = TEST_GUEST_LEAVE2; - - struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); - GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET, - "_notice_place_leave", DATA2ARG ("Leaving.")); - GNUNET_SOCIAL_guest_leave (gst, env, &guest_left, NULL); - GNUNET_PSYC_env_destroy (env); - gst = NULL; - gst_plc = NULL; -} - - -static void -schedule_guest_leave (void *cls) -{ - guest_leave (); -} - - -static void -guest_look_for_result (void *cls, - int64_t result_code, - const void *data, - uint16_t data_size) -{ - struct ResultClosure *rcls = cls; - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: guest_look_for_result: %" PRId64 "\n", - test, result_code); - GNUNET_assert (GNUNET_OK == result_code); - GNUNET_assert (6 == rcls->n); - GNUNET_free (rcls); - GNUNET_SCHEDULER_add_now (&schedule_guest_leave, NULL); -} - - -static void -guest_look_for_var (void *cls, - const struct GNUNET_MessageHeader *mod, - const char *name, - const void *value, - uint32_t value_size, - uint32_t full_value_size) -{ - struct ResultClosure *rcls = cls; - rcls->n++; - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: guest_look_for_var: %s\n%.*s\n", - test, name, value_size, (const char *) value); -} - - -static void -guest_look_for () -{ - test = TEST_GUEST_LOOK_FOR; - struct ResultClosure *rcls = GNUNET_malloc (sizeof (*rcls)); - GNUNET_SOCIAL_place_look_for (gst_plc, "_foo", guest_look_for_var, guest_look_for_result, rcls); -} - - -static void -guest_look_at_result (void *cls, int64_t result_code, - const void *data, uint16_t data_size) -{ - struct ResultClosure *rcls = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: guest_look_at_result: %" PRId64 "\n", - test, result_code); - GNUNET_assert (GNUNET_OK == result_code); - GNUNET_assert (1 == rcls->n); - GNUNET_free (rcls); - guest_look_for (); -} - - -static void -guest_look_at_var (void *cls, - const struct GNUNET_MessageHeader *mod, - const char *name, - const void *value, - uint32_t value_size, - uint32_t full_value_size) -{ - struct ResultClosure *rcls = cls; - rcls->n++; - - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: guest_look_at_var: %s\n%.*s\n", - test ,name, value_size, (const char *) value); -} - - -static void -guest_look_at () -{ - test = TEST_GUEST_LOOK_AT; - struct ResultClosure *rcls = GNUNET_malloc (sizeof (*rcls)); - GNUNET_SOCIAL_place_look_at (gst_plc, "_foo_bar", guest_look_at_var, guest_look_at_result, rcls); -} - - -static void -guest_recv_history_replay_latest_result (void *cls, int64_t result, - const void *data, uint16_t data_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Guest received latest history replay result " - "(%" PRIu32 " messages, %" PRId64 " fragments):\n" - "%.*s\n", - test, counter, result, data_size, (const char *) data); - //GNUNET_assert (2 == counter); /* message count */ - //GNUNET_assert (7 == result); /* fragment count */ - - guest_look_at (); -} - - -static void -guest_history_replay_latest () -{ - test = TEST_GUEST_HISTORY_REPLAY_LATEST; - counter = 0; - GNUNET_SOCIAL_place_history_replay_latest (gst_plc, 3, "", - GNUNET_PSYC_HISTORY_REPLAY_LOCAL, - guest_slicer, - &guest_recv_history_replay_latest_result, - NULL); -} - - -static void -guest_recv_history_replay_result (void *cls, int64_t result, - const void *data, uint16_t data_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Guest received history replay result: %" PRId64 "\n" - "%.*s\n", - test, result, data_size, (const char *) data); -// GNUNET_assert (2 == counter); /* message count */ -// GNUNET_assert (7 == result); /* fragment count */ - - guest_history_replay_latest (); -} - - -static void -guest_history_replay () -{ - test = TEST_GUEST_HISTORY_REPLAY; - counter = 0; - GNUNET_SOCIAL_place_history_replay (gst_plc, 1, 3, "", - GNUNET_PSYC_HISTORY_REPLAY_LOCAL, - guest_slicer, - &guest_recv_history_replay_result, - NULL); -} - - -static void -guest_recv_method (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_PSYC_MessageMethod *meth, - uint64_t message_id, - const char *method_name) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Guest received method for message ID %" PRIu64 ":\n" - "%s (flags: %x)\n", - test, message_id, method_name, ntohl (meth->flags)); - /** @todo FIXME: check message */ -} - - -static void -guest_recv_modifier (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg, - uint64_t message_id, - enum GNUNET_PSYC_Operator oper, - const char *name, - const void *value, - uint16_t value_size, - uint16_t full_value_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Guest received modifier for message ID %" PRIu64 ":\n" - "%c%s: %.*s (size: %u)\n", - test, message_id, oper, name, value_size, (const char *) value, value_size); - /** @todo FIXME: check modifier */ -} - -static void -guest_recv_mod_foo_bar (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg, - uint64_t message_id, - enum GNUNET_PSYC_Operator oper, - const char *name, - const void *value, - uint16_t value_size, - uint16_t full_value_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Guest received modifier matching _foo_bar for message ID %" PRIu64 ":\n" - "%c%s: %.*s (size: %u)\n", - test, message_id, oper, name, value_size, (const char *) value, value_size); - struct ResultClosure *rc = cls; - rc->n++; - /** @todo FIXME: check modifier */ -} - - -static void -guest_recv_data (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg, - uint64_t message_id, - const void *data, - uint16_t data_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Guest received data for message ID %" PRIu64 ":\n" - "%.*s\n", - test, message_id, data_size, (const char *) data); - /** @todo FIXME: check data */ -} - - -static void -guest_recv_eom (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg, - uint64_t message_id, - uint8_t is_cancelled) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Guest received end of message ID %" PRIu64 - ", cancelled: %u\n", - test, message_id, is_cancelled); - - switch (test) - { - case TEST_HOST_ANNOUNCE: - test = TEST_HOST_ANNOUNCE_END; - break; - - case TEST_HOST_ANNOUNCE_END: - guest_talk (); - break; - - case TEST_HOST_ANNOUNCE2: - test = TEST_HOST_ANNOUNCE2_END; - break; - - case TEST_HOST_ANNOUNCE2_END: - guest_history_replay (); - break; - - case TEST_GUEST_HISTORY_REPLAY: - case TEST_GUEST_HISTORY_REPLAY_LATEST: - counter++; - break; - - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "invalid test: %d\n", test); - GNUNET_assert (0); - } -} - - -static void -host_recv_method (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_PSYC_MessageMethod *meth, - uint64_t message_id, - const char *method_name) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Host received method for message ID %" PRIu64 ":\n" - "%s\n", - test, message_id, method_name); - /** @todo FIXME: check message */ -} - - -static void -host_recv_modifier (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg, - uint64_t message_id, - enum GNUNET_PSYC_Operator oper, - const char *name, - const void *value, - uint16_t value_size, - uint16_t full_value_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Host received modifier for message ID %" PRIu64 ":\n" - "%c%s: %.*s\n", - test, message_id, oper, name, value_size, (const char *) value); -} - - -static void -host_recv_data (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg, - uint64_t message_id, - const void *data, - uint16_t data_size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Host received data for message ID %" PRIu64 ":\n" - "%.*s\n", - test, message_id, data_size, (const char *) data); -} - - -static void -host_recv_eom (void *cls, - const struct GNUNET_PSYC_MessageHeader *msg, - const struct GNUNET_MessageHeader *pmsg, - uint64_t message_id, - uint8_t is_cancelled) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Host received end of message ID %" PRIu64 - ", cancelled: %u\n", - test, message_id, is_cancelled); - - switch (test) - { - case TEST_HOST_ANNOUNCE: - test = TEST_HOST_ANNOUNCE_END; - break; - - case TEST_HOST_ANNOUNCE_END: - guest_talk (); - break; - - case TEST_HOST_ANNOUNCE2: - test = TEST_HOST_ANNOUNCE2_END; - break; - - case TEST_HOST_ANNOUNCE2_END: - guest_history_replay (); - break; - - case TEST_GUEST_TALK: - host_announce2 (); - break; - - default: - if (TEST_GUEST_LEAVE <= test) - break; - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid test: #%u\n", test); - GNUNET_assert (0); - } -} - - -static void -guest_talk () -{ - test = TEST_GUEST_TALK; - - tmit = (struct TransmitClosure) {}; - tmit.env = GNUNET_PSYC_env_create (); - GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN, - "_bar_foo", DATA2ARG ("one two three")); - GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN, - "_bar_baz", DATA2ARG ("four five")); - tmit.data[0] = "zzz xxx yyy "; - tmit.data[1] = "zyx wvu tsr qpo.\n"; - tmit.data_delay[1] = 1; - tmit.data[2] = "testing ten nine eight.\n"; - tmit.data_count = 3; - - tmit.guest_talk - = GNUNET_SOCIAL_guest_talk (gst, "_converse_guest", tmit.env, - ¬ify_data, &tmit, - GNUNET_SOCIAL_TALK_NONE); -} - - -static void -host_announce () -{ - test = TEST_HOST_ANNOUNCE; - - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Host announcement.\n", test); - - tmit = (struct TransmitClosure) {}; - tmit.env = GNUNET_PSYC_env_create (); - GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN, - "_foo", DATA2ARG ("bar baz")); - GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN, - "_foo_bar", DATA2ARG ("foo bar")); - GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN, - "_foo_bar_baz", DATA2ARG ("foo bar baz")); - tmit.data[0] = "aaa bbb ccc "; - tmit.data[1] = "abc def ghi jkl.\n"; - tmit.data_delay[1] = 1; - tmit.data[2] = "testing one two three "; - tmit.data[3] = "four five.\n"; - tmit.data_count = 4; - - tmit.host_ann - = GNUNET_SOCIAL_host_announce (hst, "_converse_host", tmit.env, - ¬ify_data, &tmit, - GNUNET_SOCIAL_ANNOUNCE_NONE); -} - - -static void -host_announce2 () -{ - GNUNET_assert (2 == mod_foo_bar_rcls.n); - GNUNET_PSYC_slicer_modifier_remove (guest_slicer, "_foo_bar", - guest_recv_mod_foo_bar); - - test = TEST_HOST_ANNOUNCE2; - - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Host announcement 2.\n", test); - - tmit = (struct TransmitClosure) {}; - tmit.env = GNUNET_PSYC_env_create (); - GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN, - "_foo2", DATA2ARG ("BAR BAZ")); - GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN, - "_foo2_bar", DATA2ARG ("FOO BAR")); - GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN, - "_foo2_bar_baz", DATA2ARG ("FOO BAR BAZ")); - tmit.data[0] = "AAA BBB CCC "; - tmit.data[1] = "ABC DEF GHI JKL.\n"; - tmit.data[2] = "TESTING ONE TWO THREE.\n"; - tmit.data_count = 3; - - tmit.host_ann - = GNUNET_SOCIAL_host_announce (hst, "_converse_host_two", tmit.env, - ¬ify_data, &tmit, - GNUNET_SOCIAL_ANNOUNCE_NONE); -} - - -static void -guest_recv_entry_decision (void *cls, - int is_admitted, - const struct GNUNET_PSYC_Message *entry_msg) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Guest received entry decision (try %u): %d.\n", - test, join_req_count, is_admitted); - - if (NULL != entry_msg) - { - struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); - const char *method_name = NULL; - const void *data = NULL; - uint16_t data_size = 0; - struct GNUNET_PSYC_MessageHeader * - pmsg = GNUNET_PSYC_message_header_create_from_psyc (entry_msg); - GNUNET_PSYC_message_parse (pmsg, &method_name, env, &data, &data_size); - GNUNET_free (pmsg); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%s\n%.*s\n", - method_name, data_size, (const char *) data); - /** @todo FIXME: check response message */ - } - - switch (test) - { - case TEST_GUEST_RECV_ENTRY_DCSN_REFUSE: - GNUNET_assert (GNUNET_NO == is_admitted); - test = TEST_HOST_ANSWER_DOOR_ADMIT; - GNUNET_SOCIAL_guest_disconnect (gst, &guest_enter, NULL); - break; - - case TEST_GUEST_RECV_ENTRY_DCSN_ADMIT: - GNUNET_assert (GNUNET_YES == is_admitted); - host_announce (); - break; - - case TEST_GUEST_ENTER_BY_NAME: - GNUNET_SCHEDULER_add_now (&schedule_reconnect, NULL); - break; - - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "invalid test: %d\n", test); - GNUNET_assert (0); - } -} - - -static void -host_answer_door (void *cls, - struct GNUNET_SOCIAL_Nym *nym, - const char *method_name, - struct GNUNET_PSYC_Environment *env, - const void *data, - size_t data_size) -{ - join_req_count++; - - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Host received entry request from guest (try %u).\n", - (uint8_t) test, join_req_count); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%s\n%.*s\n", - method_name, (int) data_size, (const char *) data); - - switch (test) - { - case TEST_HOST_ANSWER_DOOR_REFUSE: - test = TEST_GUEST_RECV_ENTRY_DCSN_REFUSE; - join_resp = GNUNET_PSYC_message_create ("_notice_place_refuse", env, - DATA2ARG ("Go away!")); - GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_NO, join_resp); - break; - - case TEST_HOST_ANSWER_DOOR_ADMIT: - test = TEST_GUEST_RECV_ENTRY_DCSN_ADMIT; - // fall through - - case TEST_GUEST_ENTER_BY_NAME: - join_resp = GNUNET_PSYC_message_create ("_notice_place_admit", env, - DATA2ARG ("Welcome, nym!")); - GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_YES, join_resp); - break; - - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid test: #%u\n", test); - GNUNET_assert (0); - } -} - - -static void -guest_recv_local_enter (void *cls, int result, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, - uint64_t max_message_id) -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Guest entered local place: %d\n", - test, result); - GNUNET_assert (GNUNET_OK == result); -} - - -static void -guest_enter () -{ - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Entering place as guest.\n", test); - - struct GuestEnterMessage *emsg = &guest_enter_msg; - - emsg->method_name = "_request_enter"; - emsg->env = GNUNET_PSYC_env_create (); - GNUNET_PSYC_env_add (emsg->env, GNUNET_PSYC_OP_ASSIGN, - "_abc", "abc def", 7); - GNUNET_PSYC_env_add (emsg->env, GNUNET_PSYC_OP_ASSIGN, - "_abc_def", "abc def ghi", 11); - emsg->data = "let me in"; - emsg->data_size = strlen (emsg->data) + 1; - emsg->msg = GNUNET_PSYC_message_create (emsg->method_name, emsg->env, - emsg->data, emsg->data_size); - - gst = GNUNET_SOCIAL_guest_enter (app, guest_ego, &place_pub_key, - GNUNET_PSYC_SLAVE_JOIN_NONE, - &this_peer, 0, NULL, emsg->msg, guest_slicer, - guest_recv_local_enter, - guest_recv_entry_decision, NULL); - gst_plc = GNUNET_SOCIAL_guest_get_place (gst); - - GNUNET_SOCIAL_place_msg_proc_set (gst_plc, "_converse", - GNUNET_SOCIAL_MSG_PROC_SAVE); -} - - -static void -guest_enter_by_name () -{ - test = TEST_GUEST_ENTER_BY_NAME; - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Entering place by name as guest.\n", test); - - struct GuestEnterMessage *emsg = &guest_enter_msg; - - emsg->method_name = "_request_enter"; - emsg->env = GNUNET_PSYC_env_create (); - GNUNET_PSYC_env_add (emsg->env, GNUNET_PSYC_OP_ASSIGN, - "_abc", "abc def", 7); - GNUNET_PSYC_env_add (emsg->env, GNUNET_PSYC_OP_ASSIGN, - "_abc_def", "abc def ghi", 11); - emsg->data = "let me in"; - emsg->data_size = strlen (emsg->data) + 1; - emsg->msg = GNUNET_PSYC_message_create (emsg->method_name, emsg->env, - emsg->data, emsg->data_size); - - gst = GNUNET_SOCIAL_guest_enter_by_name (app, guest_ego, - "home.host.gnu", "let.me*in!", - emsg->msg, guest_slicer, - guest_recv_local_enter, - guest_recv_entry_decision, NULL); - gst_plc = GNUNET_SOCIAL_guest_get_place (gst); -} - - -static void -app_recv_zone_add_nym_result (void *cls, int64_t result, - const void *data, uint16_t data_size) -{ - GNUNET_assert (GNUNET_YES == result); - is_guest_nym_added = GNUNET_YES; -} - - -static void -guest_init () -{ - guest_pub_key = GNUNET_SOCIAL_ego_get_pub_key (guest_ego); - - guest_slicer = GNUNET_PSYC_slicer_create (); - GNUNET_PSYC_slicer_method_add (guest_slicer, "", NULL, - guest_recv_method, guest_recv_modifier, - guest_recv_data, guest_recv_eom, NULL); - GNUNET_PSYC_slicer_modifier_add (guest_slicer, "_foo_bar", - guest_recv_mod_foo_bar, &mod_foo_bar_rcls); - test = TEST_HOST_ANSWER_DOOR_REFUSE; - - GNUNET_SOCIAL_zone_add_nym (app, guest_ego, "host", host_pub_key, - GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES), - app_recv_zone_add_nym_result, NULL); -} - - -static void -id_host_created (void *cls, const char *emsg) -{ - if (NULL != emsg) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Test #%u: Could not create host identity: %s\n", - test, emsg); -#if ! DEBUG_TEST_SOCIAL - GNUNET_assert (0); -#endif - } - -} - - -static void -id_guest_created (void *cls, const char *emsg) -{ - if (NULL != emsg) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Test #%u: Could not create guest identity: %s\n", - test, emsg); -#if ! DEBUG_TEST_SOCIAL - GNUNET_assert (0); -#endif - } - //if (NULL != guest_ego) - // guest_init (); -} - - -static void -host_entered (void *cls, int result, - const struct GNUNET_CRYPTO_EddsaPublicKey *home_pub_key, - uint64_t max_message_id) -{ - place_pub_key = *home_pub_key; - GNUNET_CRYPTO_hash (&place_pub_key, sizeof (place_pub_key), &place_pub_hash); - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Host entered place %s\n", - test, GNUNET_h2s (&place_pub_hash)); - guest_enter (); -} - - -static void -host_enter () -{ - host_slicer = GNUNET_PSYC_slicer_create (); - GNUNET_PSYC_slicer_method_add (host_slicer, "", NULL, - host_recv_method, host_recv_modifier, - host_recv_data, host_recv_eom, NULL); - - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Test #%u: Entering place as host.\n", test); - test = TEST_HOST_ENTER; - hst = GNUNET_SOCIAL_host_enter (app, host_ego, - GNUNET_PSYC_CHANNEL_PRIVATE, - host_slicer, host_entered, - host_answer_door, host_farewell, NULL); - hst_plc = GNUNET_SOCIAL_host_get_place (hst); - - GNUNET_SOCIAL_place_msg_proc_set (hst_plc, "_converse", - GNUNET_SOCIAL_MSG_PROC_RELAY); -} - - -static void -start_app_if_ready () -{ - if (NULL == identity_host_ego || NULL == identity_guest_ego) - { - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "starting app...\n"); - app = GNUNET_SOCIAL_app_connect (cfg, - app_id, - app_recv_ego, - app_recv_host, - app_recv_guest, - app_connected, - NULL); -} - - -static void -identity_ego_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego, - void **ctx, const char *name) -{ - if (NULL != ego) - { - if (ego == identity_host_ego) - { - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Host ego deleted\n"); - } - else if (ego == identity_guest_ego) - { - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Guest ego deleted\n"); - } - else if (0 == strcmp (name, host_name)) - { - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Created ego %s\n", - name); - identity_host_ego = ego; - start_app_if_ready (); - } - else if (0 == strcmp (name, guest_name)) - { - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Created guest ego %s\n", - name); - identity_guest_ego = ego; - start_app_if_ready (); - } - } -} - - -/** - * Main function of the test, run from scheduler. - * - * @param cls NULL - * @param cfg configuration we use (also to connect to Social service) - * @param peer handle to access more of the peer (not used) - */ -static void -#if DEBUG_TEST_SOCIAL -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *c) -#else -run (void *cls, - const struct GNUNET_CONFIGURATION_Handle *c, - struct GNUNET_TESTING_Peer *peer) -#endif -{ - cfg = c; - res = 1; - end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, - &end_badly, NULL); - GNUNET_SCHEDULER_add_shutdown (&end_shutdown, - NULL); - GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer); - - id = GNUNET_IDENTITY_connect (cfg, &identity_ego_cb, NULL); - - test = TEST_IDENTITIES_CREATE; - GNUNET_IDENTITY_create (id, host_name, &id_host_created, NULL); - GNUNET_IDENTITY_create (id, guest_name, &id_guest_created, NULL); -} - - -int -main (int argc, char *argv[]) -{ - res = 1; -#if DEBUG_TEST_SOCIAL - const struct GNUNET_GETOPT_CommandLineOption opts[] = { - GNUNET_GETOPT_OPTION_END - }; - if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-social", - "test-social [options]", - opts, &run, NULL)) - return 1; -#else - if (0 != GNUNET_TESTING_peer_run ("test-social", "test_social.conf", &run, NULL)) - return 1; -#endif - return res; -} - -/* end of test_social.c */ diff --git a/src/social/test_social.conf b/src/social/test_social.conf deleted file mode 100644 index bc487760f..000000000 --- a/src/social/test_social.conf +++ /dev/null @@ -1,19 +0,0 @@ -@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf - -[PATHS] -GNUNET_TEST_HOME = $GNUNET_TMP/gnunet-test-social/ - -[social] -IMMEDIATE_START = YES - -[transport] -PLUGINS = tcp - -[nat] -DISABLEV6 = YES -ENABLE_UPNP = NO -BEHIND_NAT = NO -ALLOW_NAT = NO -INTERNAL_ADDRESS = 127.0.0.1 -EXTERNAL_ADDRESS = 127.0.0.1 - -- cgit v1.2.3