aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac13
-rw-r--r--pkgconfig/Makefile.am9
-rw-r--r--pkgconfig/gnunetmulticast.pc.in12
-rw-r--r--pkgconfig/gnunetpsyc.pc.in12
-rw-r--r--pkgconfig/gnunetpsycstore.pc.in12
-rw-r--r--pkgconfig/gnunetsocial.pc.in12
-rw-r--r--po/POTFILES.in130
-rw-r--r--src/Makefile.am8
-rw-r--r--src/include/Makefile.am13
-rw-r--r--src/include/gnunet_multicast_service.h925
-rw-r--r--src/include/gnunet_psyc_env.h340
-rw-r--r--src/include/gnunet_psyc_message.h278
-rw-r--r--src/include/gnunet_psyc_service.h1364
-rw-r--r--src/include/gnunet_psyc_slicer.h378
-rw-r--r--src/include/gnunet_psyc_util_lib.h53
-rw-r--r--src/include/gnunet_psycstore_plugin.h383
-rw-r--r--src/include/gnunet_psycstore_service.h701
-rw-r--r--src/include/gnunet_social_service.h1344
-rw-r--r--src/multicast/.gitignore7
-rw-r--r--src/multicast/Makefile.am79
-rw-r--r--src/multicast/gnunet-multicast.c79
-rw-r--r--src/multicast/gnunet-service-multicast.c2234
-rw-r--r--src/multicast/multicast.conf.in22
-rw-r--r--src/multicast/multicast.h303
-rw-r--r--src/multicast/multicast_api.c1399
-rw-r--r--src/multicast/test_multicast.c758
-rw-r--r--src/multicast/test_multicast.conf56
-rw-r--r--src/multicast/test_multicast_2peers.c520
-rw-r--r--src/multicast/test_multicast_line.conf63
-rw-r--r--src/multicast/test_multicast_multipeer.c643
-rw-r--r--src/multicast/test_multicast_star.conf64
-rw-r--r--src/psyc/.gitignore2
-rw-r--r--src/psyc/Makefile.am77
-rw-r--r--src/psyc/gnunet-service-psyc.c2860
-rw-r--r--src/psyc/psyc.conf.in12
-rw-r--r--src/psyc/psyc.h178
-rw-r--r--src/psyc/psyc_api.c1584
-rw-r--r--src/psyc/psyc_test_lib.h67
-rw-r--r--src/psyc/test_psyc.c1018
-rw-r--r--src/psyc/test_psyc.conf28
-rw-r--r--src/psyc/test_psyc2.c284
-rw-r--r--src/psyc/test_psyc_api_join.c282
-rw-r--r--src/psycstore/.gitignore5
-rw-r--r--src/psycstore/Makefile.am155
-rw-r--r--src/psycstore/gnunet-service-psycstore.c1049
-rw-r--r--src/psycstore/plugin_psycstore_mysql.c1960
-rw-r--r--src/psycstore/plugin_psycstore_postgres.c1530
-rw-r--r--src/psycstore/plugin_psycstore_sqlite.c1948
-rw-r--r--src/psycstore/psycstore.conf.in28
-rw-r--r--src/psycstore/psycstore.h520
-rw-r--r--src/psycstore/psycstore_api.c1285
-rw-r--r--src/psycstore/test_plugin_psycstore.c532
-rw-r--r--src/psycstore/test_plugin_psycstore_mysql.conf7
-rw-r--r--src/psycstore/test_plugin_psycstore_postgres.conf2
-rw-r--r--src/psycstore/test_plugin_psycstore_sqlite.conf2
-rw-r--r--src/psycstore/test_psycstore.c586
-rw-r--r--src/psycstore/test_psycstore.conf8
-rw-r--r--src/psycutil/.gitignore1
-rw-r--r--src/psycutil/Makefile.am45
-rw-r--r--src/psycutil/psyc_env.c196
-rw-r--r--src/psycutil/psyc_message.c1355
-rw-r--r--src/psycutil/psyc_slicer.c711
-rw-r--r--src/psycutil/test_psyc_env.c96
-rw-r--r--src/social/.gitignore3
-rw-r--r--src/social/Makefile.am79
-rw-r--r--src/social/gnunet-service-social.c3760
-rw-r--r--src/social/gnunet-social.c1411
-rw-r--r--src/social/social.conf.in15
-rw-r--r--src/social/social.h292
-rw-r--r--src/social/social_api.c2827
-rw-r--r--src/social/test_social.c1449
-rw-r--r--src/social/test_social.conf19
72 files changed, 62 insertions, 40420 deletions
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
1766src/integration-tests/Makefile 1766src/integration-tests/Makefile
1767src/json/Makefile 1767src/json/Makefile
1768src/hostlist/Makefile 1768src/hostlist/Makefile
1769src/multicast/Makefile
1770src/multicast/multicast.conf
1771src/my/Makefile 1769src/my/Makefile
1772src/mysql/Makefile 1770src/mysql/Makefile
1773src/namecache/Makefile 1771src/namecache/Makefile
@@ -1787,11 +1785,6 @@ src/peerinfo-tool/Makefile
1787src/peerstore/Makefile 1785src/peerstore/Makefile
1788src/peerstore/peerstore.conf 1786src/peerstore/peerstore.conf
1789src/pq/Makefile 1787src/pq/Makefile
1790src/psycutil/Makefile
1791src/psyc/Makefile
1792src/psyc/psyc.conf
1793src/psycstore/Makefile
1794src/psycstore/psycstore.conf
1795src/pt/Makefile 1788src/pt/Makefile
1796src/regex/Makefile 1789src/regex/Makefile
1797src/regex/regex.conf 1790src/regex/regex.conf
@@ -1805,8 +1798,6 @@ src/scalarproduct/Makefile
1805src/scalarproduct/scalarproduct.conf 1798src/scalarproduct/scalarproduct.conf
1806src/set/Makefile 1799src/set/Makefile
1807src/set/set.conf 1800src/set/set.conf
1808src/social/Makefile
1809src/social/social.conf
1810src/sq/Makefile 1801src/sq/Makefile
1811src/statistics/Makefile 1802src/statistics/Makefile
1812src/statistics/statistics.conf 1803src/statistics/statistics.conf
@@ -1850,21 +1841,17 @@ pkgconfig/gnunetgns.pc
1850pkgconfig/gnunethello.pc 1841pkgconfig/gnunethello.pc
1851pkgconfig/gnunetidentity.pc 1842pkgconfig/gnunetidentity.pc
1852pkgconfig/gnunetmicrophone.pc 1843pkgconfig/gnunetmicrophone.pc
1853pkgconfig/gnunetmulticast.pc
1854pkgconfig/gnunetmysql.pc 1844pkgconfig/gnunetmysql.pc
1855pkgconfig/gnunetnamestore.pc 1845pkgconfig/gnunetnamestore.pc
1856pkgconfig/gnunetnat.pc 1846pkgconfig/gnunetnat.pc
1857pkgconfig/gnunetnse.pc 1847pkgconfig/gnunetnse.pc
1858pkgconfig/gnunetpeerinfo.pc 1848pkgconfig/gnunetpeerinfo.pc
1859pkgconfig/gnunetpq.pc 1849pkgconfig/gnunetpq.pc
1860pkgconfig/gnunetpsyc.pc
1861pkgconfig/gnunetpsycstore.pc
1862pkgconfig/gnunetregex.pc 1850pkgconfig/gnunetregex.pc
1863pkgconfig/gnunetrevocation.pc 1851pkgconfig/gnunetrevocation.pc
1864pkgconfig/gnunetrps.pc 1852pkgconfig/gnunetrps.pc
1865pkgconfig/gnunetscalarproduct.pc 1853pkgconfig/gnunetscalarproduct.pc
1866pkgconfig/gnunetset.pc 1854pkgconfig/gnunetset.pc
1867pkgconfig/gnunetsocial.pc
1868pkgconfig/gnunetspeaker.pc 1855pkgconfig/gnunetspeaker.pc
1869pkgconfig/gnunetstatistics.pc 1856pkgconfig/gnunetstatistics.pc
1870pkgconfig/gnunettestbed.pc 1857pkgconfig/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 = \
19 gnunetidentity.pc \ 19 gnunetidentity.pc \
20 gnunetcadet.pc \ 20 gnunetcadet.pc \
21 gnunetmicrophone.pc \ 21 gnunetmicrophone.pc \
22 gnunetmulticast.pc \
23 gnunetmysql.pc \ 22 gnunetmysql.pc \
24 gnunetnamestore.pc \ 23 gnunetnamestore.pc \
25 gnunetnat.pc \ 24 gnunetnat.pc \
26 gnunetnse.pc \ 25 gnunetnse.pc \
27 gnunetpeerinfo.pc \ 26 gnunetpeerinfo.pc \
28 gnunetpsyc.pc \
29 gnunetpsycstore.pc \
30 gnunetregex.pc \ 27 gnunetregex.pc \
31 gnunetrevocation.pc \ 28 gnunetrevocation.pc \
32 gnunetrps.pc \ 29 gnunetrps.pc \
@@ -38,7 +35,7 @@ pcfiles = \
38 gnunettesting.pc \ 35 gnunettesting.pc \
39 gnunettransport.pc \ 36 gnunettransport.pc \
40 gnunetutil.pc \ 37 gnunetutil.pc \
41 gnunetvpn.pc 38 gnunetvpn.pc
42 39
43all-local: $(pcfiles) 40all-local: $(pcfiles)
44 41
@@ -95,9 +92,7 @@ EXTRA_DIST = \
95 gnunettransport.pc.in \ 92 gnunettransport.pc.in \
96 gnunettun.pc.in \ 93 gnunettun.pc.in \
97 gnunetutil.pc.in \ 94 gnunetutil.pc.in \
98 gnunetvpn.pc.in 95 gnunetvpn.pc.in
99 96
100CLEANFILES = $(pcfiles) 97CLEANFILES = $(pcfiles)
101AM_CPPFLAGS = -I$(top_srcdir)/src/include 98AM_CPPFLAGS = -I$(top_srcdir)/src/include
102
103
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 @@
1prefix=@prefix@
2exec_prefix=@exec_prefix@
3libdir=@libdir@
4includedir=@includedir@
5
6Name: GNUnet MULTICAST
7Description: library to multicast messages to a group of peers
8URL: https://gnunet.org
9Version: @VERSION@
10Requires:
11Libs: -L${libdir} -lgnunetmulticast
12Cflags: -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 @@
1prefix=@prefix@
2exec_prefix=@exec_prefix@
3libdir=@libdir@
4includedir=@includedir@
5
6Name: GNUnet PSYC
7Description: library for PSYC multicast channel management
8URL: https://gnunet.org
9Version: @VERSION@
10Requires:
11Libs: -L${libdir} -lgnunetpsyc
12Cflags: -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 @@
1prefix=@prefix@
2exec_prefix=@exec_prefix@
3libdir=@libdir@
4includedir=@includedir@
5
6Name: GNUnet PSYCSTORE
7Description: library to for persistent storage of PSYC messages
8URL: https://gnunet.org
9Version: @VERSION@
10Requires:
11Libs: -L${libdir} -lgnunetpsycstore
12Cflags: -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 @@
1prefix=@prefix@
2exec_prefix=@exec_prefix@
3libdir=@libdir@
4includedir=@includedir@
5
6Name: GNUnet Social
7Description: library for social interactions
8URL: https://gnunet.org
9Version: @VERSION@
10Requires:
11Libs: -L${libdir} -lgnunetsocial
12Cflags: -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
4src/arm/gnunet-arm.c 4src/arm/gnunet-arm.c
5src/arm/gnunet-service-arm.c 5src/arm/gnunet-service-arm.c
6src/arm/mockup-service.c 6src/arm/mockup-service.c
7src/ats-tests/ats-testing-experiment.c
8src/ats-tests/ats-testing-log.c
9src/ats-tests/ats-testing-preferences.c
10src/ats-tests/ats-testing-traffic.c
11src/ats-tests/ats-testing.c
12src/ats-tests/gnunet-ats-sim.c
13src/ats-tests/gnunet-solver-eval.c
14src/ats-tool/gnunet-ats.c
15src/ats/ats_api2_application.c 7src/ats/ats_api2_application.c
16src/ats/ats_api2_transport.c 8src/ats/ats_api2_transport.c
17src/ats/ats_api_connectivity.c 9src/ats/ats_api_connectivity.c
@@ -19,10 +11,10 @@ src/ats/ats_api_performance.c
19src/ats/ats_api_scanner.c 11src/ats/ats_api_scanner.c
20src/ats/ats_api_scheduling.c 12src/ats/ats_api_scheduling.c
21src/ats/gnunet-ats-solver-eval.c 13src/ats/gnunet-ats-solver-eval.c
22src/ats/gnunet-service-ats-new.c
23src/ats/gnunet-service-ats.c
24src/ats/gnunet-service-ats_addresses.c 14src/ats/gnunet-service-ats_addresses.c
15src/ats/gnunet-service-ats.c
25src/ats/gnunet-service-ats_connectivity.c 16src/ats/gnunet-service-ats_connectivity.c
17src/ats/gnunet-service-ats-new.c
26src/ats/gnunet-service-ats_normalization.c 18src/ats/gnunet-service-ats_normalization.c
27src/ats/gnunet-service-ats_performance.c 19src/ats/gnunet-service-ats_performance.c
28src/ats/gnunet-service-ats_plugins.c 20src/ats/gnunet-service-ats_plugins.c
@@ -34,6 +26,14 @@ src/ats/plugin_ats2_simple.c
34src/ats/plugin_ats_mlp.c 26src/ats/plugin_ats_mlp.c
35src/ats/plugin_ats_proportional.c 27src/ats/plugin_ats_proportional.c
36src/ats/plugin_ats_ril.c 28src/ats/plugin_ats_ril.c
29src/ats-tests/ats-testing.c
30src/ats-tests/ats-testing-experiment.c
31src/ats-tests/ats-testing-log.c
32src/ats-tests/ats-testing-preferences.c
33src/ats-tests/ats-testing-traffic.c
34src/ats-tests/gnunet-ats-sim.c
35src/ats-tests/gnunet-solver-eval.c
36src/ats-tool/gnunet-ats.c
37src/auction/gnunet-auction-create.c 37src/auction/gnunet-auction-create.c
38src/auction/gnunet-auction-info.c 38src/auction/gnunet-auction-info.c
39src/auction/gnunet-auction-join.c 39src/auction/gnunet-auction-join.c
@@ -50,8 +50,8 @@ src/cadet/cadet_api_list_peers.c
50src/cadet/cadet_api_list_tunnels.c 50src/cadet/cadet_api_list_tunnels.c
51src/cadet/cadet_test_lib.c 51src/cadet/cadet_test_lib.c
52src/cadet/desirability_table.c 52src/cadet/desirability_table.c
53src/cadet/gnunet-cadet-profiler.c
54src/cadet/gnunet-cadet.c 53src/cadet/gnunet-cadet.c
54src/cadet/gnunet-cadet-profiler.c
55src/cadet/gnunet-service-cadet.c 55src/cadet/gnunet-service-cadet.c
56src/cadet/gnunet-service-cadet_channel.c 56src/cadet/gnunet-service-cadet_channel.c
57src/cadet/gnunet-service-cadet_connection.c 57src/cadet/gnunet-service-cadet_connection.c
@@ -67,15 +67,15 @@ src/consensus/gnunet-service-consensus.c
67src/consensus/plugin_block_consensus.c 67src/consensus/plugin_block_consensus.c
68src/conversation/conversation_api.c 68src/conversation/conversation_api.c
69src/conversation/conversation_api_call.c 69src/conversation/conversation_api_call.c
70src/conversation/gnunet-conversation-test.c
71src/conversation/gnunet-conversation.c 70src/conversation/gnunet-conversation.c
72src/conversation/gnunet-helper-audio-playback-gst.c 71src/conversation/gnunet-conversation-test.c
72src/conversation/gnunet_gst.c
73src/conversation/gnunet_gst_test.c
73src/conversation/gnunet-helper-audio-playback.c 74src/conversation/gnunet-helper-audio-playback.c
74src/conversation/gnunet-helper-audio-record-gst.c 75src/conversation/gnunet-helper-audio-playback-gst.c
75src/conversation/gnunet-helper-audio-record.c 76src/conversation/gnunet-helper-audio-record.c
77src/conversation/gnunet-helper-audio-record-gst.c
76src/conversation/gnunet-service-conversation.c 78src/conversation/gnunet-service-conversation.c
77src/conversation/gnunet_gst.c
78src/conversation/gnunet_gst_test.c
79src/conversation/microphone.c 79src/conversation/microphone.c
80src/conversation/plugin_gnsrecord_conversation.c 80src/conversation/plugin_gnsrecord_conversation.c
81src/conversation/speaker.c 81src/conversation/speaker.c
@@ -111,6 +111,7 @@ src/dht/dht_api.c
111src/dht/dht_test_lib.c 111src/dht/dht_test_lib.c
112src/dht/gnunet-dht-get.c 112src/dht/gnunet-dht-get.c
113src/dht/gnunet-dht-monitor.c 113src/dht/gnunet-dht-monitor.c
114src/dht/gnunet_dht_profiler.c
114src/dht/gnunet-dht-put.c 115src/dht/gnunet-dht-put.c
115src/dht/gnunet-service-dht.c 116src/dht/gnunet-service-dht.c
116src/dht/gnunet-service-dht_clients.c 117src/dht/gnunet-service-dht_clients.c
@@ -119,7 +120,6 @@ src/dht/gnunet-service-dht_hello.c
119src/dht/gnunet-service-dht_neighbours.c 120src/dht/gnunet-service-dht_neighbours.c
120src/dht/gnunet-service-dht_nse.c 121src/dht/gnunet-service-dht_nse.c
121src/dht/gnunet-service-dht_routing.c 122src/dht/gnunet-service-dht_routing.c
122src/dht/gnunet_dht_profiler.c
123src/dht/plugin_block_dht.c 123src/dht/plugin_block_dht.c
124src/dns/dns_api.c 124src/dns/dns_api.c
125src/dns/gnunet-dns-monitor.c 125src/dns/gnunet-dns-monitor.c
@@ -133,8 +133,8 @@ src/dv/gnunet-dv.c
133src/dv/gnunet-service-dv.c 133src/dv/gnunet-service-dv.c
134src/dv/plugin_transport_dv.c 134src/dv/plugin_transport_dv.c
135src/exit/gnunet-daemon-exit.c 135src/exit/gnunet-daemon-exit.c
136src/exit/gnunet-helper-exit-windows.c
137src/exit/gnunet-helper-exit.c 136src/exit/gnunet-helper-exit.c
137src/exit/gnunet-helper-exit-windows.c
138src/fragmentation/defragmentation.c 138src/fragmentation/defragmentation.c
139src/fragmentation/fragmentation.c 139src/fragmentation/fragmentation.c
140src/fs/fs_api.c 140src/fs/fs_api.c
@@ -159,8 +159,8 @@ src/fs/gnunet-auto-share.c
159src/fs/gnunet-daemon-fsprofiler.c 159src/fs/gnunet-daemon-fsprofiler.c
160src/fs/gnunet-directory.c 160src/fs/gnunet-directory.c
161src/fs/gnunet-download.c 161src/fs/gnunet-download.c
162src/fs/gnunet-fs-profiler.c
163src/fs/gnunet-fs.c 162src/fs/gnunet-fs.c
163src/fs/gnunet-fs-profiler.c
164src/fs/gnunet-helper-fs-publish.c 164src/fs/gnunet-helper-fs-publish.c
165src/fs/gnunet-publish.c 165src/fs/gnunet-publish.c
166src/fs/gnunet-search.c 166src/fs/gnunet-search.c
@@ -180,10 +180,10 @@ src/gns/gns_tld_api.c
180src/gns/gnunet-bcd.c 180src/gns/gnunet-bcd.c
181src/gns/gnunet-dns2gns.c 181src/gns/gnunet-dns2gns.c
182src/gns/gnunet-gns-benchmark.c 182src/gns/gnunet-gns-benchmark.c
183src/gns/gnunet-gns.c
183src/gns/gnunet-gns-helper-service-w32.c 184src/gns/gnunet-gns-helper-service-w32.c
184src/gns/gnunet-gns-import.c 185src/gns/gnunet-gns-import.c
185src/gns/gnunet-gns-proxy.c 186src/gns/gnunet-gns-proxy.c
186src/gns/gnunet-gns.c
187src/gns/gnunet-service-gns.c 187src/gns/gnunet-service-gns.c
188src/gns/gnunet-service-gns_interceptor.c 188src/gns/gnunet-service-gns_interceptor.c
189src/gns/gnunet-service-gns_resolver.c 189src/gns/gnunet-service-gns_resolver.c
@@ -191,19 +191,19 @@ src/gns/nss/nss_gns.c
191src/gns/nss/nss_gns_query.c 191src/gns/nss/nss_gns_query.c
192src/gns/plugin_block_gns.c 192src/gns/plugin_block_gns.c
193src/gns/plugin_gnsrecord_gns.c 193src/gns/plugin_gnsrecord_gns.c
194src/gns/w32nsp-install.c
195src/gns/w32nsp-resolve.c
196src/gns/w32nsp-uninstall.c
197src/gns/w32nsp.c
198src/gnsrecord/gnsrecord.c 194src/gnsrecord/gnsrecord.c
199src/gnsrecord/gnsrecord_crypto.c 195src/gnsrecord/gnsrecord_crypto.c
200src/gnsrecord/gnsrecord_misc.c 196src/gnsrecord/gnsrecord_misc.c
201src/gnsrecord/gnsrecord_serialization.c 197src/gnsrecord/gnsrecord_serialization.c
202src/gnsrecord/plugin_gnsrecord_dns.c 198src/gnsrecord/plugin_gnsrecord_dns.c
199src/gns/w32nsp.c
200src/gns/w32nsp-install.c
201src/gns/w32nsp-resolve.c
202src/gns/w32nsp-uninstall.c
203src/hello/address.c 203src/hello/address.c
204src/hello/gnunet-hello.c 204src/hello/gnunet-hello.c
205src/hello/hello-ng.c
206src/hello/hello.c 205src/hello/hello.c
206src/hello/hello-ng.c
207src/hostlist/gnunet-daemon-hostlist.c 207src/hostlist/gnunet-daemon-hostlist.c
208src/hostlist/gnunet-daemon-hostlist_client.c 208src/hostlist/gnunet-daemon-hostlist_client.c
209src/hostlist/gnunet-daemon-hostlist_server.c 209src/hostlist/gnunet-daemon-hostlist_server.c
@@ -216,9 +216,6 @@ src/json/json_generator.c
216src/json/json_gnsrecord.c 216src/json/json_gnsrecord.c
217src/json/json_helper.c 217src/json/json_helper.c
218src/json/json_mhd.c 218src/json/json_mhd.c
219src/multicast/gnunet-multicast.c
220src/multicast/gnunet-service-multicast.c
221src/multicast/multicast_api.c
222src/my/my.c 219src/my/my.c
223src/my/my_query_helper.c 220src/my/my_query_helper.c
224src/my/my_result_helper.c 221src/my/my_result_helper.c
@@ -229,8 +226,8 @@ src/namecache/namecache_api.c
229src/namecache/plugin_namecache_flat.c 226src/namecache/plugin_namecache_flat.c
230src/namecache/plugin_namecache_postgres.c 227src/namecache/plugin_namecache_postgres.c
231src/namecache/plugin_namecache_sqlite.c 228src/namecache/plugin_namecache_sqlite.c
232src/namestore/gnunet-namestore-fcfsd.c
233src/namestore/gnunet-namestore.c 229src/namestore/gnunet-namestore.c
230src/namestore/gnunet-namestore-fcfsd.c
234src/namestore/gnunet-service-namestore.c 231src/namestore/gnunet-service-namestore.c
235src/namestore/gnunet-zoneimport.c 232src/namestore/gnunet-zoneimport.c
236src/namestore/namestore_api.c 233src/namestore/namestore_api.c
@@ -245,10 +242,10 @@ src/nat-auto/gnunet-service-nat-auto.c
245src/nat-auto/gnunet-service-nat-auto_legacy.c 242src/nat-auto/gnunet-service-nat-auto_legacy.c
246src/nat-auto/nat_auto_api.c 243src/nat-auto/nat_auto_api.c
247src/nat-auto/nat_auto_api_test.c 244src/nat-auto/nat_auto_api_test.c
248src/nat/gnunet-helper-nat-client-windows.c
249src/nat/gnunet-helper-nat-client.c 245src/nat/gnunet-helper-nat-client.c
250src/nat/gnunet-helper-nat-server-windows.c 246src/nat/gnunet-helper-nat-client-windows.c
251src/nat/gnunet-helper-nat-server.c 247src/nat/gnunet-helper-nat-server.c
248src/nat/gnunet-helper-nat-server-windows.c
252src/nat/gnunet-nat.c 249src/nat/gnunet-nat.c
253src/nat/gnunet-service-nat.c 250src/nat/gnunet-service-nat.c
254src/nat/gnunet-service-nat_externalip.c 251src/nat/gnunet-service-nat_externalip.c
@@ -257,16 +254,16 @@ src/nat/gnunet-service-nat_mini.c
257src/nat/gnunet-service-nat_stun.c 254src/nat/gnunet-service-nat_stun.c
258src/nat/nat_api.c 255src/nat/nat_api.c
259src/nat/nat_api_stun.c 256src/nat/nat_api_stun.c
260src/nse/gnunet-nse-profiler.c
261src/nse/gnunet-nse.c 257src/nse/gnunet-nse.c
258src/nse/gnunet-nse-profiler.c
262src/nse/gnunet-service-nse.c 259src/nse/gnunet-service-nse.c
263src/nse/nse_api.c 260src/nse/nse_api.c
264src/nt/nt.c 261src/nt/nt.c
265src/peerinfo-tool/gnunet-peerinfo.c
266src/peerinfo-tool/gnunet-peerinfo_plugins.c
267src/peerinfo/gnunet-service-peerinfo.c 262src/peerinfo/gnunet-service-peerinfo.c
268src/peerinfo/peerinfo_api.c 263src/peerinfo/peerinfo_api.c
269src/peerinfo/peerinfo_api_notify.c 264src/peerinfo/peerinfo_api_notify.c
265src/peerinfo-tool/gnunet-peerinfo.c
266src/peerinfo-tool/gnunet-peerinfo_plugins.c
270src/peerstore/gnunet-peerstore.c 267src/peerstore/gnunet-peerstore.c
271src/peerstore/gnunet-service-peerstore.c 268src/peerstore/gnunet-service-peerstore.c
272src/peerstore/peerstore_api.c 269src/peerstore/peerstore_api.c
@@ -280,16 +277,6 @@ src/pq/pq_exec.c
280src/pq/pq_prepare.c 277src/pq/pq_prepare.c
281src/pq/pq_query_helper.c 278src/pq/pq_query_helper.c
282src/pq/pq_result_helper.c 279src/pq/pq_result_helper.c
283src/psyc/gnunet-service-psyc.c
284src/psyc/psyc_api.c
285src/psycstore/gnunet-service-psycstore.c
286src/psycstore/plugin_psycstore_mysql.c
287src/psycstore/plugin_psycstore_postgres.c
288src/psycstore/plugin_psycstore_sqlite.c
289src/psycstore/psycstore_api.c
290src/psycutil/psyc_env.c
291src/psycutil/psyc_message.c
292src/psycutil/psyc_slicer.c
293src/pt/gnunet-daemon-pt.c 280src/pt/gnunet-daemon-pt.c
294src/reclaim-attribute/plugin_reclaim_attribute_gnuid.c 281src/reclaim-attribute/plugin_reclaim_attribute_gnuid.c
295src/reclaim-attribute/reclaim_attribute.c 282src/reclaim-attribute/reclaim_attribute.c
@@ -312,6 +299,7 @@ src/regex/regex_internal_dht.c
312src/regex/regex_test_graph.c 299src/regex/regex_test_graph.c
313src/regex/regex_test_lib.c 300src/regex/regex_test_lib.c
314src/regex/regex_test_random.c 301src/regex/regex_test_random.c
302src/rest/gnunet-rest-server.c
315src/rest-plugins/json_reclaim.c 303src/rest-plugins/json_reclaim.c
316src/rest-plugins/oidc_helper.c 304src/rest-plugins/oidc_helper.c
317src/rest-plugins/plugin_rest_copying.c 305src/rest-plugins/plugin_rest_copying.c
@@ -322,28 +310,27 @@ src/rest-plugins/plugin_rest_namestore.c
322src/rest-plugins/plugin_rest_openid_connect.c 310src/rest-plugins/plugin_rest_openid_connect.c
323src/rest-plugins/plugin_rest_peerinfo.c 311src/rest-plugins/plugin_rest_peerinfo.c
324src/rest-plugins/plugin_rest_reclaim.c 312src/rest-plugins/plugin_rest_reclaim.c
325src/rest/gnunet-rest-server.c
326src/rest/rest.c 313src/rest/rest.c
327src/revocation/gnunet-revocation.c 314src/revocation/gnunet-revocation.c
328src/revocation/gnunet-service-revocation.c 315src/revocation/gnunet-service-revocation.c
329src/revocation/plugin_block_revocation.c 316src/revocation/plugin_block_revocation.c
330src/revocation/revocation_api.c 317src/revocation/revocation_api.c
331src/rps/gnunet-rps-profiler.c
332src/rps/gnunet-rps.c 318src/rps/gnunet-rps.c
319src/rps/gnunet-rps-profiler.c
333src/rps/gnunet-service-rps.c 320src/rps/gnunet-service-rps.c
334src/rps/gnunet-service-rps_custommap.c 321src/rps/gnunet-service-rps_custommap.c
335src/rps/gnunet-service-rps_sampler.c 322src/rps/gnunet-service-rps_sampler.c
336src/rps/gnunet-service-rps_sampler_elem.c 323src/rps/gnunet-service-rps_sampler_elem.c
337src/rps/gnunet-service-rps_view.c 324src/rps/gnunet-service-rps_view.c
325src/rps/rps_api.c
338src/rps/rps-sampler_client.c 326src/rps/rps-sampler_client.c
339src/rps/rps-sampler_common.c 327src/rps/rps-sampler_common.c
340src/rps/rps-test_util.c 328src/rps/rps-test_util.c
341src/rps/rps_api.c
342src/scalarproduct/gnunet-scalarproduct.c 329src/scalarproduct/gnunet-scalarproduct.c
343src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c
344src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c
345src/scalarproduct/gnunet-service-scalarproduct_alice.c 330src/scalarproduct/gnunet-service-scalarproduct_alice.c
346src/scalarproduct/gnunet-service-scalarproduct_bob.c 331src/scalarproduct/gnunet-service-scalarproduct_bob.c
332src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c
333src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c
347src/scalarproduct/scalarproduct_api.c 334src/scalarproduct/scalarproduct_api.c
348src/secretsharing/gnunet-secretsharing-profiler.c 335src/secretsharing/gnunet-secretsharing-profiler.c
349src/secretsharing/gnunet-service-secretsharing.c 336src/secretsharing/gnunet-service-secretsharing.c
@@ -359,9 +346,6 @@ src/set/ibf.c
359src/set/ibf_sim.c 346src/set/ibf_sim.c
360src/set/plugin_block_set_test.c 347src/set/plugin_block_set_test.c
361src/set/set_api.c 348src/set/set_api.c
362src/social/gnunet-service-social.c
363src/social/gnunet-social.c
364src/social/social_api.c
365src/sq/sq.c 349src/sq/sq.c
366src/sq/sq_exec.c 350src/sq/sq_exec.c
367src/sq/sq_prepare.c 351src/sq/sq_prepare.c
@@ -372,16 +356,15 @@ src/statistics/gnunet-statistics.c
372src/statistics/statistics_api.c 356src/statistics/statistics_api.c
373src/template/gnunet-service-template.c 357src/template/gnunet-service-template.c
374src/template/gnunet-template.c 358src/template/gnunet-template.c
375src/testbed-logger/gnunet-service-testbed-logger.c
376src/testbed-logger/testbed_logger_api.c
377src/testbed/generate-underlay-topology.c 359src/testbed/generate-underlay-topology.c
378src/testbed/gnunet-daemon-latency-logger.c 360src/testbed/gnunet-daemon-latency-logger.c
379src/testbed/gnunet-daemon-testbed-blacklist.c 361src/testbed/gnunet-daemon-testbed-blacklist.c
380src/testbed/gnunet-daemon-testbed-underlay.c 362src/testbed/gnunet-daemon-testbed-underlay.c
381src/testbed/gnunet-helper-testbed.c 363src/testbed/gnunet-helper-testbed.c
364src/testbed/gnunet_mpi_test.c
382src/testbed/gnunet-service-test-barriers.c 365src/testbed/gnunet-service-test-barriers.c
383src/testbed/gnunet-service-testbed.c
384src/testbed/gnunet-service-testbed_barriers.c 366src/testbed/gnunet-service-testbed_barriers.c
367src/testbed/gnunet-service-testbed.c
385src/testbed/gnunet-service-testbed_cache.c 368src/testbed/gnunet-service-testbed_cache.c
386src/testbed/gnunet-service-testbed_connectionpool.c 369src/testbed/gnunet-service-testbed_connectionpool.c
387src/testbed/gnunet-service-testbed_cpustatus.c 370src/testbed/gnunet-service-testbed_cpustatus.c
@@ -389,19 +372,20 @@ src/testbed/gnunet-service-testbed_links.c
389src/testbed/gnunet-service-testbed_meminfo.c 372src/testbed/gnunet-service-testbed_meminfo.c
390src/testbed/gnunet-service-testbed_oc.c 373src/testbed/gnunet-service-testbed_oc.c
391src/testbed/gnunet-service-testbed_peers.c 374src/testbed/gnunet-service-testbed_peers.c
392src/testbed/gnunet-testbed-profiler.c
393src/testbed/gnunet_mpi_test.c
394src/testbed/gnunet_testbed_mpi_spawn.c 375src/testbed/gnunet_testbed_mpi_spawn.c
395src/testbed/testbed_api.c 376src/testbed/gnunet-testbed-profiler.c
377src/testbed-logger/gnunet-service-testbed-logger.c
378src/testbed-logger/testbed_logger_api.c
396src/testbed/testbed_api_barriers.c 379src/testbed/testbed_api_barriers.c
380src/testbed/testbed_api.c
397src/testbed/testbed_api_hosts.c 381src/testbed/testbed_api_hosts.c
398src/testbed/testbed_api_operations.c 382src/testbed/testbed_api_operations.c
399src/testbed/testbed_api_peers.c 383src/testbed/testbed_api_peers.c
400src/testbed/testbed_api_sd.c 384src/testbed/testbed_api_sd.c
401src/testbed/testbed_api_services.c 385src/testbed/testbed_api_services.c
402src/testbed/testbed_api_statistics.c 386src/testbed/testbed_api_statistics.c
403src/testbed/testbed_api_test.c
404src/testbed/testbed_api_testbed.c 387src/testbed/testbed_api_testbed.c
388src/testbed/testbed_api_test.c
405src/testbed/testbed_api_topology.c 389src/testbed/testbed_api_topology.c
406src/testbed/testbed_api_underlay.c 390src/testbed/testbed_api_underlay.c
407src/testing/gnunet-testing.c 391src/testing/gnunet-testing.c
@@ -413,29 +397,29 @@ src/transport/gnunet-communicator-tcp.c
413src/transport/gnunet-communicator-udp.c 397src/transport/gnunet-communicator-udp.c
414src/transport/gnunet-communicator-unix.c 398src/transport/gnunet-communicator-unix.c
415src/transport/gnunet-helper-transport-bluetooth.c 399src/transport/gnunet-helper-transport-bluetooth.c
416src/transport/gnunet-helper-transport-wlan-dummy.c
417src/transport/gnunet-helper-transport-wlan.c 400src/transport/gnunet-helper-transport-wlan.c
401src/transport/gnunet-helper-transport-wlan-dummy.c
418src/transport/gnunet-service-tng.c 402src/transport/gnunet-service-tng.c
419src/transport/gnunet-service-transport.c
420src/transport/gnunet-service-transport_ats.c 403src/transport/gnunet-service-transport_ats.c
404src/transport/gnunet-service-transport.c
421src/transport/gnunet-service-transport_hello.c 405src/transport/gnunet-service-transport_hello.c
422src/transport/gnunet-service-transport_manipulation.c 406src/transport/gnunet-service-transport_manipulation.c
423src/transport/gnunet-service-transport_neighbours.c 407src/transport/gnunet-service-transport_neighbours.c
424src/transport/gnunet-service-transport_plugins.c 408src/transport/gnunet-service-transport_plugins.c
425src/transport/gnunet-service-transport_validation.c 409src/transport/gnunet-service-transport_validation.c
410src/transport/gnunet-transport.c
426src/transport/gnunet-transport-certificate-creation.c 411src/transport/gnunet-transport-certificate-creation.c
427src/transport/gnunet-transport-profiler.c 412src/transport/gnunet-transport-profiler.c
428src/transport/gnunet-transport-wlan-receiver.c 413src/transport/gnunet-transport-wlan-receiver.c
429src/transport/gnunet-transport-wlan-sender.c 414src/transport/gnunet-transport-wlan-sender.c
430src/transport/gnunet-transport.c
431src/transport/plugin_transport_http_client.c 415src/transport/plugin_transport_http_client.c
432src/transport/plugin_transport_http_common.c 416src/transport/plugin_transport_http_common.c
433src/transport/plugin_transport_http_server.c 417src/transport/plugin_transport_http_server.c
434src/transport/plugin_transport_smtp.c 418src/transport/plugin_transport_smtp.c
435src/transport/plugin_transport_tcp.c 419src/transport/plugin_transport_tcp.c
436src/transport/plugin_transport_template.c 420src/transport/plugin_transport_template.c
437src/transport/plugin_transport_udp.c
438src/transport/plugin_transport_udp_broadcasting.c 421src/transport/plugin_transport_udp_broadcasting.c
422src/transport/plugin_transport_udp.c
439src/transport/plugin_transport_unix.c 423src/transport/plugin_transport_unix.c
440src/transport/plugin_transport_wlan.c 424src/transport/plugin_transport_wlan.c
441src/transport/plugin_transport_xt.c 425src/transport/plugin_transport_xt.c
@@ -444,11 +428,6 @@ src/transport/tcp_connection_legacy.c
444src/transport/tcp_server_legacy.c 428src/transport/tcp_server_legacy.c
445src/transport/tcp_server_mst_legacy.c 429src/transport/tcp_server_mst_legacy.c
446src/transport/tcp_service_legacy.c 430src/transport/tcp_service_legacy.c
447src/transport/transport-testing-filenames.c
448src/transport/transport-testing-loggers.c
449src/transport/transport-testing-main.c
450src/transport/transport-testing-send.c
451src/transport/transport-testing.c
452src/transport/transport_api2_communication.c 431src/transport/transport_api2_communication.c
453src/transport/transport_api2_core.c 432src/transport/transport_api2_core.c
454src/transport/transport_api2_monitor.c 433src/transport/transport_api2_monitor.c
@@ -460,6 +439,11 @@ src/transport/transport_api_manipulation.c
460src/transport/transport_api_monitor_peers.c 439src/transport/transport_api_monitor_peers.c
461src/transport/transport_api_monitor_plugins.c 440src/transport/transport_api_monitor_plugins.c
462src/transport/transport_api_offer_hello.c 441src/transport/transport_api_offer_hello.c
442src/transport/transport-testing.c
443src/transport/transport-testing-filenames.c
444src/transport/transport-testing-loggers.c
445src/transport/transport-testing-main.c
446src/transport/transport-testing-send.c
463src/util/bandwidth.c 447src/util/bandwidth.c
464src/util/benchmark.c 448src/util/benchmark.c
465src/util/bio.c 449src/util/bio.c
@@ -472,8 +456,8 @@ src/util/configuration_loader.c
472src/util/container_bloomfilter.c 456src/util/container_bloomfilter.c
473src/util/container_heap.c 457src/util/container_heap.c
474src/util/container_meta_data.c 458src/util/container_meta_data.c
475src/util/container_multihashmap.c
476src/util/container_multihashmap32.c 459src/util/container_multihashmap32.c
460src/util/container_multihashmap.c
477src/util/container_multipeermap.c 461src/util/container_multipeermap.c
478src/util/container_multishortmap.c 462src/util/container_multishortmap.c
479src/util/crypto_abe.c 463src/util/crypto_abe.c
@@ -495,15 +479,15 @@ src/util/dnsparser.c
495src/util/dnsstub.c 479src/util/dnsstub.c
496src/util/getopt.c 480src/util/getopt.c
497src/util/getopt_helpers.c 481src/util/getopt_helpers.c
498src/util/gnunet-config-diff.c
499src/util/gnunet-config.c 482src/util/gnunet-config.c
483src/util/gnunet-config-diff.c
500src/util/gnunet-ecc.c 484src/util/gnunet-ecc.c
501src/util/gnunet-helper-w32-console.c 485src/util/gnunet-helper-w32-console.c
502src/util/gnunet-resolver.c 486src/util/gnunet-resolver.c
503src/util/gnunet-scrypt.c 487src/util/gnunet-scrypt.c
504src/util/gnunet-service-resolver.c 488src/util/gnunet-service-resolver.c
505src/util/gnunet-timeout-w32.c
506src/util/gnunet-timeout.c 489src/util/gnunet-timeout.c
490src/util/gnunet-timeout-w32.c
507src/util/gnunet-uri.c 491src/util/gnunet-uri.c
508src/util/helper.c 492src/util/helper.c
509src/util/load.c 493src/util/load.c
@@ -532,13 +516,13 @@ src/util/tun.c
532src/util/w32cat.c 516src/util/w32cat.c
533src/util/win.c 517src/util/win.c
534src/util/winproc.c 518src/util/winproc.c
535src/vpn/gnunet-helper-vpn-windows.c
536src/vpn/gnunet-helper-vpn.c 519src/vpn/gnunet-helper-vpn.c
520src/vpn/gnunet-helper-vpn-windows.c
537src/vpn/gnunet-service-vpn.c 521src/vpn/gnunet-service-vpn.c
538src/vpn/gnunet-vpn.c 522src/vpn/gnunet-vpn.c
539src/vpn/vpn_api.c 523src/vpn/vpn_api.c
540src/zonemaster/gnunet-service-zonemaster-monitor.c
541src/zonemaster/gnunet-service-zonemaster.c 524src/zonemaster/gnunet-service-zonemaster.c
525src/zonemaster/gnunet-service-zonemaster-monitor.c
542src/fs/fs_api.h 526src/fs/fs_api.h
543src/include/compat.h 527src/include/compat.h
544src/include/gnunet_common.h 528src/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
11 11
12if HAVE_EXPERIMENTAL 12if HAVE_EXPERIMENTAL
13 EXP_DIR = \ 13 EXP_DIR = \
14 rps \ 14 rps
15 multicast \
16 psycutil \
17 psycstore \
18 psyc \
19 social
20# dv (FTBFS)
21if HAVE_ABE 15if HAVE_ABE
22if HAVE_JSON 16if HAVE_JSON
23 EXP_DIR += \ 17 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 = \
69 gnunet_hello_lib.h \ 69 gnunet_hello_lib.h \
70 gnunet_helper_lib.h \ 70 gnunet_helper_lib.h \
71 gnunet_identity_service.h \ 71 gnunet_identity_service.h \
72 gnunet_abe_lib.h \ 72 gnunet_abe_lib.h \
73 gnunet_reclaim_attribute_lib.h \ 73 gnunet_reclaim_attribute_lib.h \
74 gnunet_reclaim_attribute_plugin.h \ 74 gnunet_reclaim_attribute_plugin.h \
75 gnunet_reclaim_plugin.h \ 75 gnunet_reclaim_plugin.h \
76 gnunet_reclaim_service.h \ 76 gnunet_reclaim_service.h \
@@ -78,7 +78,6 @@ gnunetinclude_HEADERS = \
78 gnunet_load_lib.h \ 78 gnunet_load_lib.h \
79 gnunet_cadet_service.h \ 79 gnunet_cadet_service.h \
80 gnunet_microphone_lib.h \ 80 gnunet_microphone_lib.h \
81 gnunet_multicast_service.h \
82 gnunet_mst_lib.h \ 81 gnunet_mst_lib.h \
83 gnunet_mq_lib.h \ 82 gnunet_mq_lib.h \
84 gnunet_my_lib.h \ 83 gnunet_my_lib.h \
@@ -101,13 +100,6 @@ gnunetinclude_HEADERS = \
101 gnunet_peerstore_service.h \ 100 gnunet_peerstore_service.h \
102 gnunet_plugin_lib.h \ 101 gnunet_plugin_lib.h \
103 gnunet_pq_lib.h \ 102 gnunet_pq_lib.h \
104 gnunet_psycstore_plugin.h \
105 gnunet_psycstore_service.h \
106 gnunet_psyc_service.h \
107 gnunet_psyc_util_lib.h \
108 gnunet_psyc_env.h \
109 gnunet_psyc_message.h \
110 gnunet_psyc_slicer.h \
111 gnunet_program_lib.h \ 103 gnunet_program_lib.h \
112 gnunet_protocols.h \ 104 gnunet_protocols.h \
113 gnunet_resolver_service.h \ 105 gnunet_resolver_service.h \
@@ -122,7 +114,6 @@ gnunetinclude_HEADERS = \
122 gnunet_set_service.h \ 114 gnunet_set_service.h \
123 gnunet_signal_lib.h \ 115 gnunet_signal_lib.h \
124 gnunet_signatures.h \ 116 gnunet_signatures.h \
125 gnunet_social_service.h \
126 gnunet_socks.h \ 117 gnunet_socks.h \
127 gnunet_speaker_lib.h \ 118 gnunet_speaker_lib.h \
128 gnunet_sq_lib.h \ 119 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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19*/
20
21/**
22 * @author Gabor X Toth
23 * @author Christian Grothoff
24 *
25 * @file
26 * Multicast service; multicast messaging via CADET
27 *
28 * @defgroup multicast Multicast service
29 * Multicast messaging via CADET.
30 * @{
31 */
32
33#ifndef GNUNET_MULTICAST_SERVICE_H
34#define GNUNET_MULTICAST_SERVICE_H
35
36#ifdef __cplusplus
37extern "C"
38{
39#if 0 /* keep Emacsens' auto-indent happy */
40}
41#endif
42#endif
43
44#include "gnunet_util_lib.h"
45#include "gnunet_transport_service.h"
46
47/**
48 * Version number of GNUnet-multicast API.
49 */
50#define GNUNET_MULTICAST_VERSION 0x00000000
51
52/**
53 * Opaque handle for a multicast group member.
54 */
55struct GNUNET_MULTICAST_Member;
56
57/**
58 * Handle for the origin of a multicast group.
59 */
60struct GNUNET_MULTICAST_Origin;
61
62
63enum GNUNET_MULTICAST_MessageFlags
64{
65 /**
66 * First fragment of a message.
67 */
68 GNUNET_MULTICAST_MESSAGE_FIRST_FRAGMENT = 1 << 0,
69
70 /**
71 * Last fragment of a message.
72 */
73 GNUNET_MULTICAST_MESSAGE_LAST_FRAGMENT = 1 << 1,
74
75 /**
76 * OR'ed flags if message is not fragmented.
77 */
78 GNUNET_MULTICAST_MESSAGE_NOT_FRAGMENTED
79 = GNUNET_MULTICAST_MESSAGE_FIRST_FRAGMENT
80 | GNUNET_MULTICAST_MESSAGE_LAST_FRAGMENT,
81
82 /**
83 * Historic message, used only locally when replaying messages from local
84 * storage.
85 */
86 GNUNET_MULTICAST_MESSAGE_HISTORIC = 1 << 30
87
88};
89
90
91GNUNET_NETWORK_STRUCT_BEGIN
92
93/**
94 * Header of a multicast message fragment.
95 *
96 * This format is public as the replay mechanism must replay message fragments using the
97 * same format. This is needed as we want to integrity-check message fragments within
98 * the multicast layer to avoid multicasting mal-formed messages.
99 */
100struct GNUNET_MULTICAST_MessageHeader
101{
102
103 /**
104 * Header for all multicast message fragments from the origin.
105 */
106 struct GNUNET_MessageHeader header;
107
108 /**
109 * Number of hops this message fragment has taken since the origin.
110 *
111 * Helpful to determine shortest paths to the origin among honest peers for
112 * unicast requests from members. Updated at each hop and thus not signed and
113 * not secure.
114 */
115 uint32_t hop_counter GNUNET_PACKED;
116
117 /**
118 * ECC signature of the message fragment.
119 *
120 * Signature must match the public key of the multicast group.
121 */
122 struct GNUNET_CRYPTO_EddsaSignature signature;
123
124 /**
125 * Purpose for the signature and size of the signed data.
126 */
127 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
128
129 /**
130 * Number of the message fragment, monotonically increasing starting from 1.
131 */
132 uint64_t fragment_id GNUNET_PACKED;
133
134 /**
135 * Byte offset of this @e fragment of the @e message.
136 */
137 uint64_t fragment_offset GNUNET_PACKED;
138
139 /**
140 * Number of the message this fragment belongs to.
141 *
142 * Set in GNUNET_MULTICAST_origin_to_all().
143 */
144 uint64_t message_id GNUNET_PACKED;
145
146 /**
147 * Counter that monotonically increases whenever a member parts the group.
148 *
149 * Set in GNUNET_MULTICAST_origin_to_all().
150 *
151 * It has significance in case of replay requests: when a member has missed
152 * messages and gets a replay request: in this case if the @a group_generation
153 * is still the same before and after the missed messages, it means that no
154 * @e join or @e part operations happened during the missed messages.
155 */
156 uint64_t group_generation GNUNET_PACKED;
157
158 /**
159 * Flags for this message fragment.
160 *
161 * @see enum GNUNET_MULTICAST_MessageFlags
162 */
163 uint32_t flags GNUNET_PACKED;
164
165 /* Followed by message body. */
166};
167
168
169/**
170 * Header of a request from a member to the origin.
171 */
172struct GNUNET_MULTICAST_RequestHeader
173{
174 /**
175 * Header for all requests from a member to the origin.
176 */
177 struct GNUNET_MessageHeader header;
178
179 /**
180 * Public key of the sending member.
181 */
182 struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
183
184 /**
185 * ECC signature of the request fragment.
186 *
187 * Signature must match the public key of the multicast group.
188 */
189 struct GNUNET_CRYPTO_EcdsaSignature signature;
190
191 /**
192 * Purpose for the signature and size of the signed data.
193 */
194 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
195
196 /**
197 * Number of the request fragment.
198 * Monotonically increasing from 1.
199 */
200 uint64_t fragment_id GNUNET_PACKED;
201
202 /**
203 * Byte offset of this @e fragment of the @e request.
204 */
205 uint64_t fragment_offset GNUNET_PACKED;
206
207 /**
208 * Number of the request this fragment belongs to.
209 *
210 * Set in GNUNET_MULTICAST_origin_to_all().
211 */
212 uint64_t request_id GNUNET_PACKED;
213
214 /**
215 * Flags for this request.
216 */
217 enum GNUNET_MULTICAST_MessageFlags flags GNUNET_PACKED;
218
219 /* Followed by request body. */
220};
221
222GNUNET_NETWORK_STRUCT_END
223
224
225/**
226 * Maximum size of a multicast message fragment.
227 */
228#define GNUNET_MULTICAST_FRAGMENT_MAX_SIZE (63 * 1024)
229
230#define GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD \
231 (GNUNET_MULTICAST_FRAGMENT_MAX_SIZE \
232 - sizeof (struct GNUNET_MULTICAST_MessageHeader))
233
234
235/**
236 * Handle that identifies a join request.
237 *
238 * Used to match calls to #GNUNET_MULTICAST_JoinRequestCallback to the
239 * corresponding calls to #GNUNET_MULTICAST_join_decision().
240 */
241struct GNUNET_MULTICAST_JoinHandle;
242
243
244/**
245 * Function to call with the decision made for a join request.
246 *
247 * Must be called once and only once in response to an invocation of the
248 * #GNUNET_MULTICAST_JoinRequestCallback.
249 *
250 * @param jh
251 * Join request handle.
252 * @param is_admitted
253 * #GNUNET_YES if the join is approved,
254 * #GNUNET_NO if it is disapproved,
255 * #GNUNET_SYSERR if we cannot answer the request.
256 * @param relay_count
257 * Number of relays given.
258 * @param relays
259 * Array of suggested peers that might be useful relays to use
260 * when joining the multicast group (essentially a list of peers that
261 * are already part of the multicast group and might thus be willing
262 * to help with routing). If empty, only this local peer (which must
263 * be the multicast origin) is a good candidate for building the
264 * multicast tree. Note that it is unnecessary to specify our own
265 * peer identity in this array.
266 * @param join_resp
267 * Message to send in response to the joining peer;
268 * can also be used to redirect the peer to a different group at the
269 * application layer; this response is to be transmitted to the
270 * peer that issued the request even if admission is denied.
271 */
272struct GNUNET_MULTICAST_ReplayHandle *
273GNUNET_MULTICAST_join_decision (struct GNUNET_MULTICAST_JoinHandle *jh,
274 int is_admitted,
275 uint16_t relay_count,
276 const struct GNUNET_PeerIdentity *relays,
277 const struct GNUNET_MessageHeader *join_resp);
278
279
280/**
281 * Method called whenever another peer wants to join the multicast group.
282 *
283 * Implementations of this function must call GNUNET_MULTICAST_join_decision()
284 * with the decision.
285 *
286 * @param cls
287 * Closure.
288 * @param member_pub_key
289 * Public key of the member requesting join.
290 * @param join_msg
291 * Application-dependent join message from the new member.
292 * @param jh
293 * Join handle to pass to GNUNET_MULTICAST_join_decison().
294 */
295typedef void
296(*GNUNET_MULTICAST_JoinRequestCallback) (void *cls,
297 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
298 const struct GNUNET_MessageHeader *join_msg,
299 struct GNUNET_MULTICAST_JoinHandle *jh);
300
301
302/**
303 * Method called to inform about the decision in response to a join request.
304 *
305 * If @a is_admitted is not #GNUNET_YES, then the multicast service disconnects
306 * the client and the multicast member handle returned by
307 * GNUNET_MULTICAST_member_join() is invalidated.
308 *
309 * @param cls
310 * Closure.
311 * @param is_admitted
312 * #GNUNET_YES or #GNUNET_NO or #GNUNET_SYSERR
313 * @param peer
314 * The peer we are connected to and the join decision is from.
315 * @param relay_count
316 * Number of peers in the @a relays array.
317 * @param relays
318 * Peer identities of members of the group, which serve as relays
319 * and can be used to join the group at. If empty, only the origin can
320 * be used to connect to the group.
321 * @param join_msg
322 * Application-dependent join message from the origin.
323 */
324typedef void
325(*GNUNET_MULTICAST_JoinDecisionCallback) (void *cls,
326 int is_admitted,
327 const struct GNUNET_PeerIdentity *peer,
328 uint16_t relay_count,
329 const struct GNUNET_PeerIdentity *relays,
330 const struct GNUNET_MessageHeader *join_msg);
331
332
333/**
334 * Function called whenever a group member has transmitted a request
335 * to the origin (other than joining or leaving).
336 *
337 * FIXME: need to distinguish between origin cancelling a message (some fragments
338 * were sent, then the rest 'discarded') and the case where we got disconnected;
339 * right now, both would mean 'msg' is NULL, but they could be quite different...
340 * So the semantics from the receiver side of
341 * GNUNET_MULTICAST_member_to_origin_cancel() are not clear here. Maybe we
342 * should do something with the flags in this case?
343 *
344 * @param cls
345 * Closure (set from GNUNET_MULTICAST_origin_start).
346 * @param sender
347 * Identity of the sender.
348 * @param req
349 * Request to the origin.
350 * @param flags
351 * Flags for the request.
352 */
353typedef void
354(*GNUNET_MULTICAST_RequestCallback) (void *cls,
355 const struct GNUNET_MULTICAST_RequestHeader *req);
356
357
358/**
359 * Function called whenever a group member is receiving a message fragment from
360 * the origin.
361 *
362 * If admission to the group is denied, this function is called once with the
363 * response of the @e origin (as given to GNUNET_MULTICAST_join_decision()) and
364 * then a second time with NULL to indicate that the connection failed for good.
365 *
366 * FIXME: need to distinguish between origin cancelling a message (some fragments
367 * were sent, then the rest 'discarded') and the case where we got disconnected;
368 * right now, both would mean 'msg' is NULL, but they could be quite different...
369 * So the semantics from the receiver side of
370 * GNUNET_MULTICAST_origin_to_all_cancel() are not clear here.
371 *
372 * @param cls
373 * Closure (set from GNUNET_MULTICAST_member_join())
374 * @param msg
375 * Message from the origin, NULL if the origin shut down
376 * (or we were kicked out, and we should thus call
377 * GNUNET_MULTICAST_member_part() next)
378 */
379typedef void
380(*GNUNET_MULTICAST_MessageCallback) (void *cls,
381 const struct GNUNET_MULTICAST_MessageHeader *msg);
382
383
384/**
385 * Opaque handle to a replay request from the multicast service.
386 */
387struct GNUNET_MULTICAST_ReplayHandle;
388
389
390/**
391 * Functions with this signature are called whenever the multicast service needs
392 * a message fragment to be replayed by fragment_id.
393 *
394 * Implementations of this function MUST call GNUNET_MULTICAST_replay() ONCE
395 * (with a message or an error); however, if the origin is destroyed or the
396 * group is left, the replay handle must no longer be used.
397 *
398 * @param cls
399 * Closure (set from GNUNET_MULTICAST_origin_start()
400 * or GNUNET_MULTICAST_member_join()).
401 * @param member_pub_key
402 * The member requesting replay.
403 * @param fragment_id
404 * Which message fragment should be replayed.
405 * @param flags
406 * Flags for the replay.
407 * @param rh
408 * Handle to pass to message transmit function.
409 */
410typedef void
411(*GNUNET_MULTICAST_ReplayFragmentCallback) (void *cls,
412 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
413 uint64_t fragment_id,
414 uint64_t flags,
415 struct GNUNET_MULTICAST_ReplayHandle *rh);
416
417/**
418 * Functions with this signature are called whenever the multicast service needs
419 * a message fragment to be replayed by message_id and fragment_offset.
420 *
421 * Implementations of this function MUST call GNUNET_MULTICAST_replay() ONCE
422 * (with a message or an error); however, if the origin is destroyed or the
423 * group is left, the replay handle must no longer be used.
424 *
425 * @param cls
426 * Closure (set from GNUNET_MULTICAST_origin_start()
427 * or GNUNET_MULTICAST_member_join()).
428 * @param member_pub_key
429 * The member requesting replay.
430 * @param message_id
431 * Which message should be replayed.
432 * @param fragment_offset
433 * Offset of the fragment within of @a message_id to be replayed.
434 * @param flags
435 * Flags for the replay.
436 * @param rh
437 * Handle to pass to message transmit function.
438 */
439typedef void
440(*GNUNET_MULTICAST_ReplayMessageCallback) (void *cls,
441 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
442 uint64_t message_id,
443 uint64_t fragment_offset,
444 uint64_t flags,
445 struct GNUNET_MULTICAST_ReplayHandle *rh);
446
447
448/**
449 * Possible error codes during replay.
450 */
451enum GNUNET_MULTICAST_ReplayErrorCode
452{
453
454 /**
455 * Everything is fine.
456 */
457 GNUNET_MULTICAST_REC_OK = 0,
458
459 /**
460 * Message fragment not found in the message store.
461 *
462 * Either discarded if it is too old, or not arrived yet if this member has
463 * missed some messages.
464 */
465 GNUNET_MULTICAST_REC_NOT_FOUND = 1,
466
467 /**
468 * Fragment ID counter was larger than the highest counter this
469 * replay function has ever encountered; thus it is likely the
470 * origin never sent it and we're at the HEAD of the multicast
471 * stream as far as this node is concerned.
472 *
473 * FIXME: needed?
474 */
475 GNUNET_MULTICAST_REC_PAST_HEAD = 2,
476
477 /**
478 * Access is denied to the requested fragment, membership test did not pass.
479 */
480 GNUNET_MULTICAST_REC_ACCESS_DENIED = 3,
481
482 /**
483 * Internal error (i.e. database error). Try some other peer.
484 */
485 GNUNET_MULTICAST_REC_INTERNAL_ERROR = 4
486
487};
488
489
490/**
491 * Replay a message fragment for the multicast group.
492 *
493 * @param rh
494 * Replay handle identifying which replay operation was requested.
495 * @param msg
496 * Replayed message fragment, NULL if not found / an error occurred.
497 * @param ec
498 * Error code. See enum GNUNET_MULTICAST_ReplayErrorCode
499 * If not #GNUNET_MULTICAST_REC_OK, the replay handle is invalidated.
500 */
501void
502GNUNET_MULTICAST_replay_response (struct GNUNET_MULTICAST_ReplayHandle *rh,
503 const struct GNUNET_MessageHeader *msg,
504 enum GNUNET_MULTICAST_ReplayErrorCode ec);
505
506
507/**
508 * Indicate the end of the replay session.
509 *
510 * Invalidates the replay handle.
511 *
512 * @param rh Replay session to end.
513 */
514void
515GNUNET_MULTICAST_replay_response_end (struct GNUNET_MULTICAST_ReplayHandle *rh);
516
517
518/**
519 * Function called to provide data for a transmission for a replay.
520 *
521 * @see GNUNET_MULTICAST_replay2()
522 */
523typedef int
524(*GNUNET_MULTICAST_ReplayTransmitNotify) (void *cls,
525 size_t *data_size,
526 void *data);
527
528
529/**
530 * Replay a message for the multicast group.
531 *
532 * @param rh
533 * Replay handle identifying which replay operation was requested.
534 * @param notify
535 * Function to call to get the message.
536 * @param notify_cls
537 * Closure for @a notify.
538 */
539void
540GNUNET_MULTICAST_replay_response2 (struct GNUNET_MULTICAST_ReplayHandle *rh,
541 GNUNET_MULTICAST_ReplayTransmitNotify notify,
542 void *notify_cls);
543
544
545/**
546 * Start a multicast group.
547 *
548 * Peers that issue GNUNET_MULTICAST_member_join() can transmit a join request
549 * to either an existing group member or to the origin. If the joining is
550 * approved, the member is cleared for @e replay and will begin to receive
551 * messages transmitted to the group. If joining is disapproved, the failed
552 * candidate will be given a response. Members in the group can send messages
553 * to the origin.
554 *
555 * TODO: This function could optionally offer to advertise the origin in the
556 * P2P overlay network(where?) under the respective public key so that other
557 * peers can find an alternate PeerId to join it. Higher level protocols may
558 * however provide other means of solving the problem of the offline host
559 * (see secushare specs about that) and therefore merely need a way to provide
560 * a list of possible PeerIds.
561 *
562 * @param cfg
563 * Configuration to use.
564 * @param priv_key
565 * ECC key that will be used to sign messages for this
566 * multicast session; public key is used to identify the multicast group;
567 * @param max_fragment_id
568 * Maximum fragment ID already sent to the group.
569 * 0 for a new group.
570 * @param join_request_cb
571 * Function called to approve / disapprove joining of a peer.
572 * @param replay_frag_cb
573 * Function that can be called to replay a message fragment.
574 * @param replay_msg_cb
575 * Function that can be called to replay a message.
576 * @param request_cb
577 * Function called with message fragments from group members.
578 * @param message_cb
579 * Function called with the message fragments sent to the
580 * network by GNUNET_MULTICAST_origin_to_all(). These message fragments
581 * should be stored for answering replay requests later.
582 * @param cls
583 * Closure for the various callbacks that follow.
584 *
585 * @return Handle for the origin, NULL on error.
586 */
587struct GNUNET_MULTICAST_Origin *
588GNUNET_MULTICAST_origin_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
589 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv_key,
590 uint64_t max_fragment_id,
591 GNUNET_MULTICAST_JoinRequestCallback join_request_cb,
592 GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb,
593 GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb,
594 GNUNET_MULTICAST_RequestCallback request_cb,
595 GNUNET_MULTICAST_MessageCallback message_cb,
596 void *cls);
597
598/**
599 * Function called to provide data for a transmission from the origin to all
600 * members.
601 *
602 * Note that returning #GNUNET_OK or #GNUNET_SYSERR (but not #GNUNET_NO)
603 * invalidates the respective transmission handle.
604 *
605 * @param cls
606 * Closure.
607 * @param[in,out] data_size
608 * Initially set to the number of bytes available in
609 * @a data, should be set to the number of bytes written to data.
610 * @param[out] data
611 * Where to write the body of the message to give to the
612 * method. The function must copy at most @a data_size bytes to @a data.
613 *
614 * @return #GNUNET_SYSERR on error (fatal, aborts transmission)
615 * #GNUNET_NO on success, if more data is to be transmitted later.
616 * Should be used if @a data_size was not big enough to take all the
617 * data. If 0 is returned in @a data_size the transmission is paused,
618 * and can be resumed with GNUNET_MULTICAST_origin_to_all_resume().
619 * #GNUNET_YES if this completes the transmission (all data supplied)
620 * @deprecated should move to MQ-style API!
621 */
622typedef int
623(*GNUNET_MULTICAST_OriginTransmitNotify) (void *cls,
624 size_t *data_size,
625 void *data);
626
627
628/**
629 * Handle for a request to send a message to all multicast group members
630 * (from the origin).
631 */
632struct GNUNET_MULTICAST_OriginTransmitHandle;
633
634
635/**
636 * Send a message to the multicast group.
637 *
638 * @param origin
639 * Handle to the multicast group.
640 * @param message_id
641 * Application layer ID for the message. Opaque to multicast.
642 * @param group_generation
643 * Group generation of the message. Documented in
644 * struct GNUNET_MULTICAST_MessageHeader.
645 * @param notify
646 * Function to call to get the message.
647 * @param notify_cls
648 * Closure for @a notify.
649 *
650 * @return NULL on error (i.e. request already pending).
651 * @deprecated should move to MQ-style API!
652 */
653struct GNUNET_MULTICAST_OriginTransmitHandle *
654GNUNET_MULTICAST_origin_to_all (struct GNUNET_MULTICAST_Origin *origin,
655 uint64_t message_id,
656 uint64_t group_generation,
657 GNUNET_MULTICAST_OriginTransmitNotify notify,
658 void *notify_cls);
659
660
661
662/**
663 * Resume message transmission to multicast group.
664 *
665 * @param th Transmission to cancel.
666 */
667void
668GNUNET_MULTICAST_origin_to_all_resume (struct GNUNET_MULTICAST_OriginTransmitHandle *th);
669
670
671/**
672 * Cancel request for message transmission to multicast group.
673 *
674 * @param th Transmission to cancel.
675 */
676void
677GNUNET_MULTICAST_origin_to_all_cancel (struct GNUNET_MULTICAST_OriginTransmitHandle *th);
678
679
680/**
681 * Stop a multicast group.
682 *
683 * @param origin Multicast group to stop.
684 */
685void
686GNUNET_MULTICAST_origin_stop (struct GNUNET_MULTICAST_Origin *origin,
687 GNUNET_ContinuationCallback stop_cb,
688 void *stop_cls);
689
690
691/**
692 * Join a multicast group.
693 *
694 * The entity joining is always the local peer. Further information about the
695 * candidate can be provided in @a join_msg. If the join fails, the
696 * @a message_cb is invoked with a (failure) response and then with NULL. If
697 * the join succeeds, outstanding (state) messages and ongoing multicast
698 * messages will be given to the @a message_cb until the member decides to part
699 * the group. The @a mem_test_cb and @a replay_cb functions may be called at
700 * anytime by the multicast service to support relaying messages to other
701 * members of the group.
702 *
703 * @param cfg
704 * Configuration to use.
705 * @param group_key
706 * ECC public key that identifies the group to join.
707 * @param member_pub_key
708 * ECC key that identifies the member
709 * and used to sign requests sent to the origin.
710 * @param origin
711 * Peer ID of the origin to send unicast requsets to. If NULL,
712 * unicast requests are sent back via multiple hops on the reverse path
713 * of multicast messages.
714 * @param relay_count
715 * Number of peers in the @a relays array.
716 * @param relays
717 * Peer identities of members of the group, which serve as relays
718 * and can be used to join the group at. and send the @a join_request to.
719 * If empty, the @a join_request is sent directly to the @a origin.
720 * @param join_msg
721 * Application-dependent join message to be passed to the peer @a origin.
722 * @param join_request_cb
723 * Function called to approve / disapprove joining of a peer.
724 * @param join_decision_cb
725 * Function called to inform about the join decision.
726 * @param replay_frag_cb
727 * Function that can be called to replay message fragments
728 * this peer already knows from this group. NULL if this
729 * client is unable to support replay.
730 * @param replay_msg_cb
731 * Function that can be called to replay message fragments
732 * this peer already knows from this group. NULL if this
733 * client is unable to support replay.
734 * @param message_cb
735 * Function to be called for all message fragments we
736 * receive from the group, excluding those our @a replay_cb
737 * already has.
738 * @param cls
739 * Closure for callbacks.
740 *
741 * @return Handle for the member, NULL on error.
742 */
743struct GNUNET_MULTICAST_Member *
744GNUNET_MULTICAST_member_join (const struct GNUNET_CONFIGURATION_Handle *cfg,
745 const struct GNUNET_CRYPTO_EddsaPublicKey *group_key,
746 const struct GNUNET_CRYPTO_EcdsaPrivateKey *member_pub_key,
747 const struct GNUNET_PeerIdentity *origin,
748 uint16_t relay_count,
749 const struct GNUNET_PeerIdentity *relays,
750 const struct GNUNET_MessageHeader *join_request,
751 GNUNET_MULTICAST_JoinRequestCallback join_request_cb,
752 GNUNET_MULTICAST_JoinDecisionCallback join_decision_cb,
753 GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb,
754 GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb,
755 GNUNET_MULTICAST_MessageCallback message_cb,
756 void *cls);
757
758/**
759 * Handle for a replay request.
760 */
761struct GNUNET_MULTICAST_MemberReplayHandle;
762
763
764/**
765 * Request a fragment to be replayed by fragment ID.
766 *
767 * Useful if messages below the @e max_known_fragment_id given when joining are
768 * needed and not known to the client.
769 *
770 * @param member
771 * Membership handle.
772 * @param fragment_id
773 * ID of a message fragment that this client would like to see replayed.
774 * @param flags
775 * Additional flags for the replay request.
776 * It is used and defined by GNUNET_MULTICAST_ReplayFragmentCallback
777 *
778 * @return Replay request handle, NULL on error.
779 */
780struct GNUNET_MULTICAST_MemberReplayHandle *
781GNUNET_MULTICAST_member_replay_fragment (struct GNUNET_MULTICAST_Member *member,
782 uint64_t fragment_id,
783 uint64_t flags);
784
785
786/**
787 * Request a message fr to be replayed.
788 *
789 * Useful if messages below the @e max_known_fragment_id given when joining are
790 * needed and not known to the client.
791 *
792 * @param member
793 * Membership handle.
794 * @param message_id
795 * ID of the message this client would like to see replayed.
796 * @param fragment_offset
797 * Offset of the fragment within the message to replay.
798 * @param flags
799 * Additional flags for the replay request.
800 * It is used & defined by GNUNET_MULTICAST_ReplayMessageCallback
801 *
802 * @return Replay request handle, NULL on error.
803 */
804struct GNUNET_MULTICAST_MemberReplayHandle *
805GNUNET_MULTICAST_member_replay_message (struct GNUNET_MULTICAST_Member *member,
806 uint64_t message_id,
807 uint64_t fragment_offset,
808 uint64_t flags);
809
810
811/**
812 * Cancel a replay request.
813 *
814 * @param rh
815 * Request to cancel.
816 */
817void
818GNUNET_MULTICAST_member_replay_cancel (struct GNUNET_MULTICAST_MemberReplayHandle *rh);
819
820
821/**
822 * Part a multicast group.
823 *
824 * Disconnects from all group members and invalidates the @a member handle.
825 *
826 * An application-dependent part message can be transmitted beforehand using
827 * #GNUNET_MULTICAST_member_to_origin())
828 *
829 * @param member
830 * Membership handle.
831 */
832void
833GNUNET_MULTICAST_member_part (struct GNUNET_MULTICAST_Member *member,
834 GNUNET_ContinuationCallback part_cb,
835 void *part_cls);
836
837
838/**
839 * Function called to provide data for a transmission from a member to the origin.
840 *
841 * Note that returning #GNUNET_OK or #GNUNET_SYSERR (but not #GNUNET_NO)
842 * invalidates the respective transmission handle.
843 *
844 * @param cls
845 * Closure.
846 * @param[in,out] data_size
847 * Initially set to the number of bytes available in
848 * @a data, should be set to the number of bytes written to data.
849 * @param[out] data
850 * Where to write the body of the message to give to the
851 * method. The function must copy at most @a data_size bytes to @a data.
852 *
853 * @return #GNUNET_SYSERR on error (fatal, aborts transmission)
854 * #GNUNET_NO on success, if more data is to be transmitted later.
855 * Should be used if @a data_size was not big enough to take all the
856 * data. If 0 is returned in @a data_size the transmission is paused,
857 * and can be resumed with GNUNET_MULTICAST_member_to_origin_resume().
858 * #GNUNET_YES if this completes the transmission (all data supplied)
859 * @deprecated should move to MQ-style API!
860 */
861typedef int
862(*GNUNET_MULTICAST_MemberTransmitNotify) (void *cls,
863 size_t *data_size,
864 void *data);
865
866
867/**
868 * Handle for a message to be delivered from a member to the origin.
869 */
870struct GNUNET_MULTICAST_MemberTransmitHandle;
871
872
873/**
874 * Send a message to the origin of the multicast group.
875 *
876 * @param member
877 * Membership handle.
878 * @param request_id
879 * Application layer ID for the request. Opaque to multicast.
880 * @param notify
881 * Callback to call to get the message.
882 * @param notify_cls
883 * Closure for @a notify.
884 *
885 * @return Handle to cancel request, NULL on error (i.e. request already pending).
886 * @deprecated should move to MQ-style API!
887 */
888struct GNUNET_MULTICAST_MemberTransmitHandle *
889GNUNET_MULTICAST_member_to_origin (struct GNUNET_MULTICAST_Member *member,
890 uint64_t request_id,
891 GNUNET_MULTICAST_MemberTransmitNotify notify,
892 void *notify_cls);
893
894
895/**
896 * Resume message transmission to origin.
897 *
898 * @param th
899 * Transmission to cancel.
900 */
901void
902GNUNET_MULTICAST_member_to_origin_resume (struct GNUNET_MULTICAST_MemberTransmitHandle *th);
903
904
905/**
906 * Cancel request for message transmission to origin.
907 *
908 * @param th
909 * Transmission to cancel.
910 */
911void
912GNUNET_MULTICAST_member_to_origin_cancel (struct GNUNET_MULTICAST_MemberTransmitHandle *th);
913
914
915#if 0 /* keep Emacsens' auto-indent happy */
916{
917#endif
918#ifdef __cplusplus
919}
920#endif
921
922/* ifndef GNUNET_MULTICAST_SERVICE_H */
923#endif
924
925/** @} */ /* 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 @@
1/*
2 * This file is part of GNUnet.
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @author Gabor X Toth
23 *
24 * @file
25 * PSYC Environment library
26 *
27 * @defgroup psyc-util-env PSYC Utilities library: Environment
28 * Environment data structure operations for PSYC and Social messages.
29 *
30 * Library providing operations for the @e environment of
31 * PSYC and Social messages, and for (de)serializing variable values.
32 *
33 * @{
34 */
35
36
37#ifndef GNUNET_PSYC_ENV_H
38#define GNUNET_PSYC_ENV_H
39
40#ifdef __cplusplus
41extern "C"
42{
43#if 0 /* keep Emacsens' auto-indent happy */
44}
45#endif
46#endif
47
48
49/**
50 * Possible operations on PSYC state (persistent) and transient variables (per message).
51 */
52enum GNUNET_PSYC_Operator
53{
54 /**
55 * Set value of a transient variable.
56 */
57 GNUNET_PSYC_OP_SET = ':',
58
59 /**
60 * Assign value for a persistent state variable.
61 *
62 * If an assigned value is NULL, the variable is deleted.
63 */
64 GNUNET_PSYC_OP_ASSIGN = '=',
65
66 /**
67 * Augment state variable.
68 *
69 * Used for appending strings, adding numbers, and adding new items to a list or dictionary.
70 */
71 GNUNET_PSYC_OP_AUGMENT = '+',
72
73 /**
74 * Diminish state variable.
75 *
76 * Used for subtracting numbers, and removing items from a list or dictionary.
77 */
78 GNUNET_PSYC_OP_DIMINISH = '-',
79
80 /**
81 * Update state variable.
82 *
83 * Used for modifying a single item of a list or dictionary.
84 */
85 GNUNET_PSYC_OP_UPDATE = '@',
86};
87
88
89/**
90 * PSYC variable types.
91 */
92enum GNUNET_PSYC_Type
93{
94 GNUNET_PSYC_TYPE_DATA = 0,
95 GNUNET_PSYC_TYPE_NUMBER,
96 GNUNET_PSYC_TYPE_LIST,
97 GNUNET_PSYC_TYPE_DICT
98};
99
100
101/**
102 * PSYC state modifier.
103 */
104struct GNUNET_PSYC_Modifier
105{
106 /**
107 * State operation.
108 */
109 enum GNUNET_PSYC_Operator oper;
110
111 /**
112 * Variable name.
113 */
114 const char *name;
115
116 /**
117 * Size of @a value.
118 */
119 size_t value_size;
120
121 /**
122 * Value of variable.
123 */
124 const void *value;
125
126 /**
127 * Next modifier.
128 */
129 struct GNUNET_PSYC_Modifier *next;
130
131 /**
132 * Previous modifier.
133 */
134 struct GNUNET_PSYC_Modifier *prev;
135};
136
137
138/**
139 * Environment for a message.
140 *
141 * Contains modifiers.
142 */
143struct GNUNET_PSYC_Environment;
144
145
146/**
147 * Create an environment.
148 *
149 * @return A newly allocated environment.
150 */
151struct GNUNET_PSYC_Environment *
152GNUNET_PSYC_env_create ();
153
154
155/**
156 * Add a modifier to the environment.
157 *
158 * @param env The environment.
159 * @param oper Operation to perform.
160 * @param name Name of the variable.
161 * @param value Value of the variable.
162 * @param value_size Size of @a value.
163 */
164void
165GNUNET_PSYC_env_add (struct GNUNET_PSYC_Environment *env,
166 enum GNUNET_PSYC_Operator oper, const char *name,
167 const void *value, size_t value_size);
168
169
170/**
171 * Get the first modifier of the environment.
172 */
173struct GNUNET_PSYC_Modifier *
174GNUNET_PSYC_env_head (const struct GNUNET_PSYC_Environment *env);
175
176
177
178/**
179 * Get the last modifier of the environment.
180 */
181struct GNUNET_PSYC_Modifier *
182GNUNET_PSYC_env_tail (const struct GNUNET_PSYC_Environment *env);
183
184
185/**
186 * Remove a modifier from the environment.
187 */
188void
189GNUNET_PSYC_env_remove (struct GNUNET_PSYC_Environment *env,
190 struct GNUNET_PSYC_Modifier *mod);
191
192
193/**
194 * Remove a modifier at the beginning of the environment.
195 */
196int
197GNUNET_PSYC_env_shift (struct GNUNET_PSYC_Environment *env,
198 enum GNUNET_PSYC_Operator *oper, const char **name,
199 const void **value, size_t *value_size);
200
201
202/**
203 * Iterator for modifiers in the environment.
204 *
205 * @param cls Closure.
206 * @param mod Modifier.
207 *
208 * @return #GNUNET_YES to continue iterating,
209 * #GNUNET_NO to stop.
210 */
211typedef int
212(*GNUNET_PSYC_Iterator) (void *cls, enum GNUNET_PSYC_Operator oper,
213 const char *name, const char *value,
214 uint32_t value_size);
215
216
217/**
218 * Iterate through all modifiers in the environment.
219 *
220 * @param env The environment.
221 * @param it Iterator.
222 * @param it_cls Closure for iterator.
223 */
224void
225GNUNET_PSYC_env_iterate (const struct GNUNET_PSYC_Environment *env,
226 GNUNET_PSYC_Iterator it, void *it_cls);
227
228
229/**
230 * Get the number of modifiers in the environment.
231 *
232 * @param env The environment.
233 *
234 * @return Number of modifiers.
235 */
236size_t
237GNUNET_PSYC_env_get_count (const struct GNUNET_PSYC_Environment *env);
238
239
240/**
241 * Destroy an environment.
242 *
243 * @param env The environment to destroy.
244 */
245void
246GNUNET_PSYC_env_destroy (struct GNUNET_PSYC_Environment *env);
247
248
249/**
250 * Get the type of variable.
251 *
252 * @param name Name of the variable.
253 *
254 * @return Variable type.
255 */
256enum GNUNET_PSYC_Type
257GNUNET_PSYC_var_get_type (char *name);
258
259
260/**
261 * Perform an operation on a variable.
262 *
263 * @param name Name of variable.
264 * @param current_value Current value of variable.
265 * @param current_value_size Size of @a current_value.
266 * @param oper Operator.
267 * @param args Arguments for the operation.
268 * @param args_size Size of @a args.
269 * @param return_value Return value.
270 * @param return_value_size Size of @a return_value.
271 *
272 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
273 */
274int
275GNUNET_PSYC_operation (char *name, void *current_value, size_t current_value_size,
276 enum GNUNET_PSYC_Operator oper, void *args, size_t args_size,
277 void **return_value, size_t *return_value_size);
278
279
280/**
281 * Get the variable's value as an integer.
282 *
283 * @param size Size of value.
284 * @param value Raw value of variable.
285 * @param[out] number Value converted to a 64-bit integer.
286 *
287 * @return #GNUNET_OK on success, #GNUNET_SYSERR if an error occurred (e.g. the value is invalid).
288 */
289int
290GNUNET_PSYC_value_to_number (size_t size, const void *value, int64_t *number);
291
292
293/**
294 * Get the variable's value as a dictionary.
295 *
296 * @param size Size of value.
297 * @param value Raw value of variable.
298 * @param[out] dict A newly created hashmap holding the elements of the dictionary.
299 *
300 * @return #GNUNET_OK on success, #GNUNET_SYSERR if an error occurred (e.g. the value is invalid).
301 */
302int
303GNUNET_PSYC_value_to_dict (size_t size, const void *value, struct GNUNET_CONTAINER_MultiHashMap **dict);
304
305
306/**
307 * Create a PSYC variable value from an integer.
308 *
309 * @param number The number to convert.
310 * @param[out] value_size Size of returned value.
311 *
312 * @return A newly allocated value or NULL on error.
313 */
314void *
315GNUNET_PSYC_value_from_number (int64_t number, size_t *value_size);
316
317
318/**
319 * Create a PSYC variable value from a dictionary.
320 *
321 * @param dict The dict to convert.
322 * @param[out] value_size Size of returned value.
323 *
324 * @return A newly allocated value or NULL on error.
325 */
326void *
327GNUNET_PSYC_value_from_dict (struct GNUNET_CONTAINER_MultiHashMap *dict, size_t *value_size);
328
329
330#if 0 /* keep Emacsens' auto-indent happy */
331{
332#endif
333#ifdef __cplusplus
334}
335#endif
336
337/* ifndef GNUNET_PSYC_ENV_H */
338#endif
339
340/** @} */ /* 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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19*/
20
21/**
22 * @author Gabor X Toth
23 *
24 * @file
25 * PSYC message utilities; receiving/transmitting/logging PSYC messages
26 *
27 * @defgroup psyc-util-message PSYC Utilities library: Messages
28 * Receiving, transmitting, logging PSYC messages.
29 * @{
30 */
31
32#ifndef GNUNET_PSYC_MESSAGE_H
33#define GNUNET_PSYC_MESSAGE_H
34
35#ifdef __cplusplus
36extern "C"
37{
38#if 0 /* keep Emacsens' auto-indent happy */
39}
40#endif
41#endif
42
43
44#include "gnunet_util_lib.h"
45#include "gnunet_psyc_util_lib.h"
46#include "gnunet_psyc_service.h"
47
48
49/**
50 * Create a PSYC message.
51 *
52 * @param method_name
53 * PSYC method for the message.
54 * @param env
55 * Environment for the message.
56 * @param data
57 * Data payload for the message.
58 * @param data_size
59 * Size of @a data.
60 *
61 * @return Message header with size information,
62 * followed by the message parts.
63 *
64 * FIXME: arg order
65 */
66struct GNUNET_PSYC_Message *
67GNUNET_PSYC_message_create (const char *method_name,
68 const struct GNUNET_PSYC_Environment *env,
69 const void *data,
70 size_t data_size);
71
72/**
73 * Parse PSYC message.
74 *
75 * @param msg
76 * The PSYC message to parse.
77 * @param env
78 * The environment for the message with a list of modifiers.
79 * @param[out] method_name
80 * Pointer to the method name inside @a pmsg.
81 * @param[out] data
82 * Pointer to data inside @a pmsg.
83 * @param[out] data_size
84 * Size of @data is written here.
85 *
86 * @return #GNUNET_OK on success,
87 * #GNUNET_SYSERR on parse error.
88 *
89 * FIXME: arg order
90 */
91int
92GNUNET_PSYC_message_parse (const struct GNUNET_PSYC_MessageHeader *msg,
93 const char **method_name,
94 struct GNUNET_PSYC_Environment *env,
95 const void **data,
96 uint16_t *data_size);
97
98
99void
100GNUNET_PSYC_log_message (enum GNUNET_ErrorType kind,
101 const struct GNUNET_MessageHeader *msg);
102
103
104struct GNUNET_PSYC_TransmitHandle;
105
106/**
107 * Create a transmission handle.
108 */
109struct GNUNET_PSYC_TransmitHandle *
110GNUNET_PSYC_transmit_create (struct GNUNET_MQ_Handle *mq);
111
112
113/**
114 * Destroy a transmission handle.
115 */
116void
117GNUNET_PSYC_transmit_destroy (struct GNUNET_PSYC_TransmitHandle *tmit);
118
119
120/**
121 * Transmit a message.
122 *
123 * @param tmit
124 * Transmission handle.
125 * @param method_name
126 * Which method should be invoked.
127 * @param env
128 * Environment for the message.
129 * Should stay available until the first call to notify_data.
130 * Can be NULL if there are no modifiers or @a notify_mod is
131 * provided instead.
132 * @param notify_mod
133 * Function to call to obtain modifiers.
134 * Can be NULL if there are no modifiers or @a env is provided instead.
135 * @param notify_data
136 * Function to call to obtain fragments of the data.
137 * @param notify_cls
138 * Closure for @a notify_mod and @a notify_data.
139 * @param flags
140 * Flags for the message being transmitted.
141 *
142 * @return #GNUNET_OK if the transmission was started.
143 * #GNUNET_SYSERR if another transmission is already going on.
144 */
145int
146GNUNET_PSYC_transmit_message (struct GNUNET_PSYC_TransmitHandle *tmit,
147 const char *method_name,
148 const struct GNUNET_PSYC_Environment *env,
149 GNUNET_PSYC_TransmitNotifyModifier notify_mod,
150 GNUNET_PSYC_TransmitNotifyData notify_data,
151 void *notify_cls,
152 uint32_t flags);
153
154
155/**
156 * Resume transmission.
157 *
158 * @param tmit Transmission handle.
159 */
160void
161GNUNET_PSYC_transmit_resume (struct GNUNET_PSYC_TransmitHandle *tmit);
162
163
164/**
165 * Abort transmission request.
166 *
167 * @param tmit Transmission handle.
168 */
169void
170GNUNET_PSYC_transmit_cancel (struct GNUNET_PSYC_TransmitHandle *tmit);
171
172
173/**
174 * Got acknowledgement of a transmitted message part, continue transmission.
175 *
176 * @param tmit Transmission handle.
177 */
178void
179GNUNET_PSYC_transmit_got_ack (struct GNUNET_PSYC_TransmitHandle *tmit);
180
181
182struct GNUNET_PSYC_ReceiveHandle;
183
184
185/**
186 * Create handle for receiving messages.
187 */
188struct GNUNET_PSYC_ReceiveHandle *
189GNUNET_PSYC_receive_create (GNUNET_PSYC_MessageCallback message_cb,
190 GNUNET_PSYC_MessagePartCallback message_part_cb,
191 void *cb_cls);
192
193
194/**
195 * Destroy handle for receiving messages.
196 */
197void
198GNUNET_PSYC_receive_destroy (struct GNUNET_PSYC_ReceiveHandle *recv);
199
200
201/**
202 * Reset stored data related to the last received message.
203 */
204void
205GNUNET_PSYC_receive_reset (struct GNUNET_PSYC_ReceiveHandle *recv);
206
207
208/**
209 * Handle incoming PSYC message.
210 *
211 * @param recv
212 * Receive handle.
213 * @param msg
214 * The message.
215 *
216 * @return #GNUNET_OK on success,
217 * #GNUNET_SYSERR on receive error.
218 */
219int
220GNUNET_PSYC_receive_message (struct GNUNET_PSYC_ReceiveHandle *recv,
221 const struct GNUNET_PSYC_MessageHeader *msg);
222
223
224/**
225 * Check if @a data contains a series of valid message parts.
226 *
227 * @param data_size
228 * Size of @a data.
229 * @param data
230 * Data.
231 * @param[out] first_ptype
232 * Type of first message part.
233 * @param[out] last_ptype
234 * Type of last message part.
235 *
236 * @return Number of message parts found in @a data.
237 * or GNUNET_SYSERR if the message contains invalid parts.
238 */
239int
240GNUNET_PSYC_receive_check_parts (uint16_t data_size, const char *data,
241 uint16_t *first_ptype, uint16_t *last_ptype);
242
243
244/**
245 * Initialize PSYC message header.
246 */
247void
248GNUNET_PSYC_message_header_init (struct GNUNET_PSYC_MessageHeader *pmsg,
249 const struct GNUNET_MULTICAST_MessageHeader *mmsg,
250 uint32_t flags);
251
252
253/**
254 * Create a new PSYC message header from a multicast message for sending it to clients.
255 */
256struct GNUNET_PSYC_MessageHeader *
257GNUNET_PSYC_message_header_create (const struct GNUNET_MULTICAST_MessageHeader *mmsg,
258 uint32_t flags);
259
260
261/**
262 * Create a new PSYC message header from a PSYC message.
263 */
264struct GNUNET_PSYC_MessageHeader *
265GNUNET_PSYC_message_header_create_from_psyc (const struct GNUNET_PSYC_Message *msg);
266
267
268#if 0 /* keep Emacsens' auto-indent happy */
269{
270#endif
271#ifdef __cplusplus
272}
273#endif
274
275/* ifndef GNUNET_PSYC_MESSAGE_H */
276#endif
277
278/** @} */ /* 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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19*/
20
21/**
22 * @author Gabor X Toth
23 * @author Christian Grothoff
24 *
25 * @file
26 * PSYC service
27 *
28 * @defgroup psyc PSYC service
29 * Send/receive messages in PSYC channels and access the PSYC Store.
30 *
31 * Note that clients of this API are NOT expected to understand the PSYC message
32 * format, only the semantics! Parsing (and serializing) the PSYC stream format
33 * is done within the implementation of the libgnunetpsyc library, and this API
34 * deliberately exposes as little as possible of the actual data stream format
35 * to the application!
36 *
37 * NOTE:
38 * - this API does not know about PSYC's "root" and "places";
39 * there is no 'root' in GNUnet-PSYC as we're decentralized;
40 * 'places' and 'persons' are combined within the same
41 * abstraction, that of a "channel". Channels are identified
42 * and accessed in this API using a public/private key.
43 * Higher-level applications should use NAMES within GNS
44 * to obtain public keys, and the distinction between
45 * 'places' and 'persons' can then be made with the help
46 * of the naming system (and/or conventions).
47 * Channels are (as in PSYC) organized into a hierarchy; each
48 * channel master (the one with the private key) is then
49 * the operator of the multicast group (its Origin in
50 * the terminology of the multicast API).
51 * - The API supports passing large amounts of data using
52 * 'streaming' for the argument passed to a method. State
53 * and variables must fit into memory and cannot be streamed
54 * (thus, no passing of 4 GB of data in a variable;
55 * once we implement this, we might want to create a
56 * @c \#define for the maximum size of a variable).
57 * - PSYC defines standard variables, methods, etc. This
58 * library deliberately abstracts over all of these; a
59 * higher-level API should combine the naming system (GNS)
60 * and standard methods (_converse, _notice, _request,
61 * _warning, _error etc) and variables (_action, _color,
62 * _time, etc). However, this API does take over the
63 * routing variables, specifically '_context' (channel),
64 * and '_source'. We only kind-of support '_target', as
65 * the target is either everyone in the group or the
66 * origin, and never just a single member of the group;
67 * for such individual messages, an application needs to
68 * construct an 'inbox' channel where the master (only)
69 * receives messages (but never forwards; private responses
70 * would be transmitted by joining the senders 'inbox'
71 * channel -- or a inbox#bob subchannel). The
72 * goal for all of this is to keep the abstractions in this
73 * API minimal: interaction with multicast, try \& slice,
74 * state/variable/channel management. Higher-level
75 * operations belong elsewhere (so maybe this API should
76 * be called 'PSYC-low', whereas a higher-level API
77 * implementing defaults for standard methods and
78 * variables might be called 'PSYC-std' or 'PSYC-high'.
79 *
80 * In PSYC terminology this is simply called the "PSYC
81 * routing layer" and the abstractions, for instance in
82 * psyced, are quite similar. The higher one is called
83 * "PSYC entity layer." In the text rendering of the
84 * protocol the two are separated by an empty line. See
85 * http://about.psyc.eu/Spec:Packet and related. --lynX
86 *
87 * @{
88 */
89
90#ifndef GNUNET_PSYC_SERVICE_H
91#define GNUNET_PSYC_SERVICE_H
92
93#ifdef __cplusplus
94extern "C"
95{
96#if 0 /* keep Emacsens' auto-indent happy */
97}
98#endif
99#endif
100
101#include "gnunet_util_lib.h"
102#include "gnunet_multicast_service.h"
103//Mingw work around
104#ifdef MINGW
105 # ifndef UINT64_MAX
106 # define UINT64_MAX 0xffffffffffffffffULL
107 # endif
108#endif
109
110/**
111 * Version number of GNUnet-PSYC API.
112 */
113#define GNUNET_PSYC_VERSION 0x00000000
114
115
116/**
117 * Policy flags for a channel.
118 */
119enum GNUNET_PSYC_ChannelFlags
120{
121 /**
122 * Admission must be confirmed by the master.
123 */
124 GNUNET_PSYC_CHANNEL_ADMISSION_CONTROL = 1 << 0,
125
126 /**
127 * Past messages are only available to slaves who were admitted at the time
128 * they were sent to the channel.
129 */
130 GNUNET_PSYC_CHANNEL_RESTRICTED_HISTORY = 1 << 1
131};
132
133
134/**
135 * PSYC channel policies.
136 */
137enum GNUNET_PSYC_Policy
138{
139 /**
140 * Anyone can join the channel, without announcing their presence;
141 * all messages are always public and can be distributed freely.
142 * Joins may be announced, but this is not required.
143 */
144 GNUNET_PSYC_CHANNEL_ANONYMOUS = 0,
145
146 /**
147 * The master must approve membership to the channel, messages must only be
148 * distributed to current channel slaves. This includes the channel
149 * state as well as transient messages.
150 */
151 GNUNET_PSYC_CHANNEL_PRIVATE
152 = GNUNET_PSYC_CHANNEL_ADMISSION_CONTROL
153 | GNUNET_PSYC_CHANNEL_RESTRICTED_HISTORY
154
155#if IDEAS_FOR_FUTURE
156 /**
157 * Anyone can freely join the channel (no approval required);
158 * however, messages must only be distributed to current channel
159 * slaves, so the master must still acknowledge that the slave
160 * joined before transient messages are delivered. As approval is
161 * guaranteed, the presistent channel state can be synchronized freely
162 * immediately, prior to master confirmation.
163 */
164 GNUNET_PSYC_CHANNEL_OPEN
165 = GNUNET_PSYC_CHANNEL_RESTRICTED_HISTORY,
166
167 /**
168 * The master must approve joins to the channel, but past messages can be
169 * freely distributed to slaves.
170 */
171 GNUNET_PSYC_CHANNEL_CLOSED
172 = GNUNET_PSYC_CHANNEL_ADMISSION_CONTROL,
173#endif
174};
175
176
177enum GNUNET_PSYC_MessageFlags
178{
179 /**
180 * Default / no flags.
181 */
182 GNUNET_PSYC_MESSAGE_DEFAULT = 0,
183
184 /**
185 * Historic message, retrieved from PSYCstore.
186 */
187 GNUNET_PSYC_MESSAGE_HISTORIC = 1 << 0,
188
189 /**
190 * Request from slave to master.
191 */
192 GNUNET_PSYC_MESSAGE_REQUEST = 1 << 1,
193
194 /**
195 * Message can be delivered out of order.
196 */
197 GNUNET_PSYC_MESSAGE_ORDER_ANY = 1 << 2
198};
199
200
201/**
202 * Values for the @a state_delta field of GNUNET_PSYC_MessageHeader.
203 */
204enum GNUNET_PSYC_StateDeltaValues
205{
206 GNUNET_PSYC_STATE_RESET = 0,
207
208 GNUNET_PSYC_STATE_NOT_MODIFIED = UINT64_MAX
209};
210
211
212GNUNET_NETWORK_STRUCT_BEGIN
213
214/**
215 * A PSYC message.
216 *
217 * Used for single-fragment messages e.g. in a join request or response.
218 */
219struct GNUNET_PSYC_Message
220{
221 /**
222 * Message header with size and type information.
223 */
224 struct GNUNET_MessageHeader header;
225
226 /* Followed by concatenated PSYC message parts:
227 * messages with GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_* types
228 */
229};
230
231
232/**
233 * Header of a PSYC message.
234 *
235 * The PSYC service adds this when delivering the message to local clients,
236 * not present on the multicast layer.
237 */
238struct GNUNET_PSYC_MessageHeader
239{
240 /**
241 * Generic message header with size and type information.
242 */
243 struct GNUNET_MessageHeader header;
244
245 /**
246 * Flags for this message fragment.
247 *
248 * @see enum GNUNET_PSYC_MessageFlags
249 */
250 uint32_t flags GNUNET_PACKED;
251
252 /**
253 * Number of the message this message part belongs to.
254 * Monotonically increasing from 1.
255 */
256 uint64_t message_id GNUNET_PACKED;
257
258 /**
259 * Byte offset of this @e fragment of the @e message.
260 */
261 uint64_t fragment_offset GNUNET_PACKED;
262
263 /**
264 * Sending slave's public key.
265 * Not set if the message is from the master.
266 */
267 struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key;
268
269 /* Followed by concatenated PSYC message parts:
270 * messages with GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_* types
271 */
272};
273
274
275/**
276 * The method of a message.
277 */
278struct GNUNET_PSYC_MessageMethod
279{
280 /**
281 * Type: GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD
282 */
283 struct GNUNET_MessageHeader header;
284
285 /**
286 * OR'ed GNUNET_PSYC_MasterTransmitFlags
287 */
288 uint32_t flags GNUNET_PACKED;
289
290 /**
291 * Number of message IDs since the last message that contained state
292 * operations. @see enum GNUNET_PSYC_StateDeltaValues
293 */
294 uint64_t state_delta GNUNET_PACKED;
295
296 /* Followed by NUL-terminated method name. */
297};
298
299
300/**
301 * A modifier of a message.
302 */
303struct GNUNET_PSYC_MessageModifier
304{
305 /**
306 * Type: GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER
307 */
308 struct GNUNET_MessageHeader header;
309
310 /**
311 * Size of value.
312 */
313 uint32_t value_size GNUNET_PACKED;
314
315 /**
316 * Size of name, including NUL terminator.
317 */
318 uint16_t name_size GNUNET_PACKED;
319
320 /**
321 * enum GNUNET_PSYC_Operator
322 */
323 uint8_t oper;
324
325 /* Followed by NUL-terminated name, then the value. */
326};
327
328
329struct GNUNET_PSYC_CountersResultMessage
330{
331 /**
332 * Type: GNUNET_MESSAGE_TYPE_PSYC_RESULT_COUNTERS
333 */
334 struct GNUNET_MessageHeader header;
335
336 /**
337 * Status code for the operation.
338 */
339 uint32_t result_code GNUNET_PACKED;
340
341 /**
342 * Last message ID sent to the channel.
343 */
344 uint64_t max_message_id GNUNET_PACKED;
345};
346
347
348/**
349 * Join request sent to a PSYC master.
350 */
351struct GNUNET_PSYC_JoinRequestMessage
352{
353 /**
354 * Type: GNUNET_MESSAGE_TYPE_PSYC_MASTER_JOIN_REQUEST
355 */
356 struct GNUNET_MessageHeader header;
357 /**
358 * Public key of the joining slave.
359 */
360 struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key;
361
362 /* Followed by struct GNUNET_MessageHeader join_request */
363};
364
365
366/**
367 * Join decision sent in reply to a join request.
368 */
369struct GNUNET_PSYC_JoinDecisionMessage
370{
371 /**
372 * Type: GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION
373 */
374 struct GNUNET_MessageHeader header;
375
376 /**
377 * #GNUNET_YES if the slave was admitted.
378 */
379 int32_t is_admitted;
380
381 /**
382 * Public key of the joining slave.
383 * Only set when the master is sending the decision,
384 * not set when a slave is receiving it.
385 */
386 struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key;
387
388 /* Followed by struct GNUNET_MessageHeader join_response */
389};
390
391
392enum GNUNET_PSYC_HistoryReplayFlags
393{
394 /**
395 * Replay locally available messages.
396 */
397 GNUNET_PSYC_HISTORY_REPLAY_LOCAL = 0,
398
399 /**
400 * Replay messages from remote peers if not found locally.
401 */
402 GNUNET_PSYC_HISTORY_REPLAY_REMOTE = 1,
403};
404
405
406struct GNUNET_PSYC_HistoryRequestMessage
407{
408 /**
409 * Type: GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_HISTORY_REPLAY
410 */
411 struct GNUNET_MessageHeader header;
412
413 /**
414 * @see enum GNUNET_PSYC_HistoryReplayFlags
415 */
416 uint32_t flags GNUNET_PACKED;
417
418 /**
419 * ID for this operation.
420 */
421 uint64_t op_id GNUNET_PACKED;
422
423 uint64_t start_message_id GNUNET_PACKED;
424
425 uint64_t end_message_id GNUNET_PACKED;
426
427 uint64_t message_limit GNUNET_PACKED;
428
429 /* Followed by NUL-terminated method name prefix. */
430};
431
432
433struct GNUNET_PSYC_StateRequestMessage
434{
435 /**
436 * Types:
437 * - GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_STATE_GET
438 * - GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_STATE_GET_PREFIX
439 */
440 struct GNUNET_MessageHeader header;
441
442 uint32_t reserved GNUNET_PACKED;
443
444 /**
445 * ID for this operation.
446 */
447 uint64_t op_id GNUNET_PACKED;
448
449 /* Followed by NUL-terminated name. */
450};
451
452
453/**** service -> library ****/
454
455
456/**
457 * Answer from service to client about last operation.
458 */
459struct GNUNET_PSYC_OperationResultMessage
460{
461 /**
462 * Types:
463 * - GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE
464 * - GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_STATE_RESULT
465 */
466 struct GNUNET_MessageHeader header;
467
468 uint32_t reserved GNUNET_PACKED;
469
470 /**
471 * Operation ID.
472 */
473 uint64_t op_id GNUNET_PACKED;
474
475 /**
476 * Status code for the operation.
477 */
478 uint64_t result_code GNUNET_PACKED;
479
480 /* Followed by:
481 * - on error: NUL-terminated error message
482 * - on success: one of the following message types
483 *
484 * For a STATE_RESULT, one of:
485 * - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER
486 * - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT
487 * - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END
488 */
489};
490
491GNUNET_NETWORK_STRUCT_END
492
493
494#define GNUNET_PSYC_MODIFIER_MAX_PAYLOAD \
495 GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD \
496 - sizeof (struct GNUNET_PSYC_MessageModifier)
497
498#define GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD \
499 GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD \
500 - sizeof (struct GNUNET_MessageHeader)
501
502#define GNUNET_PSYC_DATA_MAX_PAYLOAD \
503 GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD \
504 - sizeof (struct GNUNET_MessageHeader)
505
506
507/**
508 * PSYC message part processing states.
509 */
510enum GNUNET_PSYC_MessageState
511{
512 GNUNET_PSYC_MESSAGE_STATE_START = 0,
513 GNUNET_PSYC_MESSAGE_STATE_HEADER = 1,
514 GNUNET_PSYC_MESSAGE_STATE_METHOD = 2,
515 GNUNET_PSYC_MESSAGE_STATE_MODIFIER = 3,
516 GNUNET_PSYC_MESSAGE_STATE_MOD_CONT = 4,
517 GNUNET_PSYC_MESSAGE_STATE_DATA = 5,
518 GNUNET_PSYC_MESSAGE_STATE_END = 6,
519 GNUNET_PSYC_MESSAGE_STATE_CANCEL = 7,
520 GNUNET_PSYC_MESSAGE_STATE_ERROR = 8,
521};
522
523
524/**
525 * Handle that identifies a join request.
526 *
527 * Used to match calls to #GNUNET_PSYC_JoinCallback to the
528 * corresponding calls to GNUNET_PSYC_join_decision().
529 */
530struct GNUNET_PSYC_JoinHandle;
531
532
533/**
534 * Method called from PSYC upon receiving a message.
535 *
536 * @param cls Closure.
537 * @param message_id Sequence number of the message.
538 * @param flags OR'ed GNUNET_PSYC_MessageFlags
539 * @param msg Message part, one of the following types:
540 */
541typedef void
542(*GNUNET_PSYC_MessageCallback) (void *cls,
543 const struct GNUNET_PSYC_MessageHeader *msg);
544
545
546/**
547 * Method called from PSYC upon receiving part of a message.
548 *
549 * @param cls
550 * Closure.
551 * @param slave_pub_key
552 * Public key of the slave sending the message.
553 * Only set for channel master.
554 * @param message_id
555 * Sequence number of the message.
556 * @param flags
557 * OR'ed GNUNET_PSYC_MessageFlags
558 * @param fragment_offset
559 * Multicast message fragment offset.
560 * @param msg Message part, one of the following types:
561 * - #GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_HEADER
562 * - #GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD
563 * - #GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER
564 * - #GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT
565 * - #GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA
566 * or NULL if an error occurred while receiving a message.
567 */
568typedef void
569(*GNUNET_PSYC_MessagePartCallback) (void *cls,
570 const struct GNUNET_PSYC_MessageHeader *msg,
571 const struct GNUNET_MessageHeader *pmsg);
572
573
574/**
575 * Method called from PSYC upon receiving a join request.
576 *
577 * @param cls
578 * Closure.
579 * @param slave_pub_key
580 * Public key of the slave requesting join.
581 * @param join_msg
582 * Join message sent along with the request.
583 * @param jh
584 * Join handle to use with GNUNET_PSYC_join_decision()
585 */
586typedef void
587(*GNUNET_PSYC_JoinRequestCallback) (void *cls,
588 const struct GNUNET_PSYC_JoinRequestMessage *req,
589 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key,
590 const struct GNUNET_PSYC_Message *join_msg,
591 struct GNUNET_PSYC_JoinHandle *jh);
592
593
594/**
595 * Function to call with the decision made for a join request.
596 *
597 * Must be called once and only once in response to an invocation of the
598 * #GNUNET_PSYC_JoinCallback.
599 *
600 * @param jh Join request handle.
601 * @param is_admitted
602 * #GNUNET_YES if the join is approved,
603 * #GNUNET_NO if it is disapproved,
604 * #GNUNET_SYSERR if we cannot answer the request.
605 * @param relay_count Number of relays given.
606 * @param relays Array of suggested peers that might be useful relays to use
607 * when joining the multicast group (essentially a list of peers that
608 * are already part of the multicast group and might thus be willing
609 * to help with routing). If empty, only this local peer (which must
610 * be the multicast origin) is a good candidate for building the
611 * multicast tree. Note that it is unnecessary to specify our own
612 * peer identity in this array.
613 * @param join_resp Application-dependent join response message to send along
614 * with the decision.
615 *
616 * @return #GNUNET_OK on success,
617 * #GNUNET_SYSERR if @a join_resp is too large.
618 */
619int
620GNUNET_PSYC_join_decision (struct GNUNET_PSYC_JoinHandle *jh,
621 int is_admitted,
622 uint32_t relay_count,
623 const struct GNUNET_PeerIdentity *relays,
624 const struct GNUNET_PSYC_Message *join_resp);
625
626
627/**
628 * Handle for the master of a PSYC channel.
629 */
630struct GNUNET_PSYC_Master;
631
632
633/**
634 * Function called once we are connected to the PSYC service
635 * and the channel master is started.
636 *
637 * Also called when we reconnected to the service
638 * after the connection closed unexpectedly.
639 *
640 * @param cls
641 * Closure.
642 * @param result
643 * #GNUNET_YES if there were already messages sent to the channel,
644 * #GNUNET_NO if the message history is empty,
645 * #GNUNET_SYSERR on error.
646 * @param max_message_id
647 * Last message ID sent to the channel.
648 */
649typedef void
650(*GNUNET_PSYC_MasterStartCallback) (void *cls, int result,
651 uint64_t max_message_id);
652
653
654/**
655 * Start a PSYC master channel.
656 *
657 * Will start a multicast group identified by the given ECC key. Messages
658 * received from group members will be given to the respective handler methods.
659 * If a new member wants to join a group, the "join" method handler will be
660 * invoked; the join handler must then generate a "join" message to approve the
661 * joining of the new member. The channel can also change group membership
662 * without explicit requests. Note that PSYC doesn't itself "understand" join
663 * or part messages, the respective methods must call other PSYC functions to
664 * inform PSYC about the meaning of the respective events.
665 *
666 * @param cfg Configuration to use (to connect to PSYC service).
667 * @param channel_key ECC key that will be used to sign messages for this
668 * PSYC session. The public key is used to identify the PSYC channel.
669 * Note that end-users will usually not use the private key directly, but
670 * rather look it up in GNS for places managed by other users, or select
671 * a file with the private key(s) when setting up their own channels
672 * FIXME: we'll likely want to use NOT the p521 curve here, but a cheaper
673 * one in the future.
674 * @param policy Channel policy specifying join and history restrictions.
675 * Used to automate join decisions.
676 * @param master_start_cb Function to invoke after the channel master started.
677 * @param join_request_cb Function to invoke when a slave wants to join.
678 * @param message_cb Function to invoke on message parts sent to the channel
679 * and received from slaves
680 * @param cls Closure for @a method and @a join_cb.
681 *
682 * @return Handle for the channel master, NULL on error.
683 */
684struct GNUNET_PSYC_Master *
685GNUNET_PSYC_master_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
686 const struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key,
687 enum GNUNET_PSYC_Policy policy,
688 GNUNET_PSYC_MasterStartCallback master_start_cb,
689 GNUNET_PSYC_JoinRequestCallback join_request_cb,
690 GNUNET_PSYC_MessageCallback message_cb,
691 GNUNET_PSYC_MessagePartCallback message_part_cb,
692 void *cls);
693
694
695/**
696 * Function called to provide data for a transmission via PSYC.
697 *
698 * Note that returning #GNUNET_YES or #GNUNET_SYSERR (but not #GNUNET_NO)
699 * invalidates the respective transmission handle.
700 *
701 * @param cls Closure.
702 * @param[in,out] data_size Initially set to the number of bytes available in
703 * @a data, should be set to the number of bytes written to data.
704 * @param[out] data Where to write the body of the message to give to the
705 * method. The function must copy at most @a data_size bytes to @a data.
706 * @return #GNUNET_SYSERR on error (fatal, aborts transmission)
707 * #GNUNET_NO on success, if more data is to be transmitted later.
708 * Should be used if @a data_size was not big enough to take all the
709 * data. If 0 is returned in @a data_size the transmission is paused,
710 * and can be resumed with GNUNET_PSYC_master_transmit_resume().
711 * #GNUNET_YES if this completes the transmission (all data supplied)
712 */
713typedef int
714(*GNUNET_PSYC_TransmitNotifyData) (void *cls,
715 uint16_t *data_size,
716 void *data);
717
718/**
719 * Function called to provide a modifier for a transmission via PSYC.
720 *
721 * Note that returning #GNUNET_YES or #GNUNET_SYSERR (but not #GNUNET_NO)
722 * invalidates the respective transmission handle.
723 *
724 * @param cls Closure.
725 * @param[in,out] data_size Initially set to the number of bytes available in
726 * @a data, should be set to the number of bytes written to data.
727 * @param[out] data Where to write the modifier's name and value.
728 * The function must copy at most @a data_size bytes to @a data.
729 * When this callback is first called for a modifier, @a data should
730 * contain: "name\0value". If the whole value does not fit, subsequent
731 * calls to this function should write continuations of the value to
732 * @a data.
733 * @param[out] oper Where to write the operator of the modifier.
734 * Only needed during the first call to this callback at the beginning
735 * of the modifier. In case of subsequent calls asking for value
736 * continuations @a oper is set to #NULL.
737 * @param[out] full_value_size Where to write the full size of the value.
738 * Only needed during the first call to this callback at the beginning
739 * of the modifier. In case of subsequent calls asking for value
740 * continuations @a value_size is set to #NULL.
741 * @return #GNUNET_SYSERR on error (fatal, aborts transmission)
742 * #GNUNET_NO on success, if more data is to be transmitted later.
743 * Should be used if @a data_size was not big enough to take all the
744 * data for the modifier's value (the name must be always returned
745 * during the first call to this callback).
746 * If 0 is returned in @a data_size the transmission is paused,
747 * and can be resumed with GNUNET_PSYC_master_transmit_resume().
748 * #GNUNET_YES if this completes the modifier (the whole value is supplied).
749 */
750typedef int
751(*GNUNET_PSYC_TransmitNotifyModifier) (void *cls,
752 uint16_t *data_size,
753 void *data,
754 uint8_t *oper,
755 uint32_t *full_value_size);
756
757/**
758 * Flags for transmitting messages to a channel by the master.
759 */
760enum GNUNET_PSYC_MasterTransmitFlags
761{
762 GNUNET_PSYC_MASTER_TRANSMIT_NONE = 0,
763
764 /**
765 * Whether this message should reset the channel state,
766 * i.e. remove all previously stored state variables.
767 */
768
769 GNUNET_PSYC_MASTER_TRANSMIT_STATE_RESET = 1 << 0,
770
771 /**
772 * Whether this message contains any state modifiers.
773 */
774 GNUNET_PSYC_MASTER_TRANSMIT_STATE_MODIFY = 1 << 1,
775
776 /**
777 * Add PSYC header variable with the hash of the current channel state.
778 */
779 GNUNET_PSYC_MASTER_TRANSMIT_STATE_HASH = 1 << 2,
780
781 /**
782 * Whether we need to increment the group generation counter after
783 * transmitting this message.
784 */
785 GNUNET_PSYC_MASTER_TRANSMIT_INC_GROUP_GEN = 1 << 3
786};
787
788
789/**
790 * Handle for a pending PSYC transmission operation.
791 */
792struct GNUNET_PSYC_MasterTransmitHandle;
793
794
795/**
796 * Send a message to call a method to all members in the PSYC channel.
797 *
798 * @param master Handle to the PSYC channel.
799 * @param method_name Which method should be invoked.
800 * @param notify_mod Function to call to obtain modifiers.
801 * @param notify_data Function to call to obtain fragments of the data.
802 * @param notify_cls Closure for @a notify_mod and @a notify_data.
803 * @param flags Flags for the message being transmitted.
804 * @return Transmission handle, NULL on error (i.e. more than one request queued).
805 */
806struct GNUNET_PSYC_MasterTransmitHandle *
807GNUNET_PSYC_master_transmit (struct GNUNET_PSYC_Master *master,
808 const char *method_name,
809 GNUNET_PSYC_TransmitNotifyModifier notify_mod,
810 GNUNET_PSYC_TransmitNotifyData notify_data,
811 void *notify_cls,
812 enum GNUNET_PSYC_MasterTransmitFlags flags);
813
814
815/**
816 * Resume transmission to the channel.
817 *
818 * @param th Handle of the request that is being resumed.
819 */
820void
821GNUNET_PSYC_master_transmit_resume (struct GNUNET_PSYC_MasterTransmitHandle *th);
822
823
824/**
825 * Abort transmission request to channel.
826 *
827 * @param th Handle of the request that is being aborted.
828 */
829void
830GNUNET_PSYC_master_transmit_cancel (struct GNUNET_PSYC_MasterTransmitHandle *th);
831
832
833/**
834 * Relay a message
835 *
836 * @param master Handle to the PSYC channel.
837 * @param method_name Which method should be invoked.
838 * @param notify_mod Function to call to obtain modifiers.
839 * @param notify_data Function to call to obtain fragments of the data.
840 * @param notify_cls Closure for @a notify_mod and @a notify_data.
841 * @param flags Flags for the message being transmitted.
842 * @return Transmission handle, NULL on error (i.e. more than one request queued).
843 */
844struct GNUNET_PSYC_MasterTransmitHandle *
845GNUNET_PSYC_master_relay (struct GNUNET_PSYC_Master *master,
846 uint64_t message_id);
847
848
849/**
850 * Stop a PSYC master channel.
851 *
852 * @param master
853 * PSYC channel master to stop.
854 * @param keep_active
855 * Keep place active after last application disconnected.
856 * @param stop_cb
857 * Function called after the master stopped
858 * and disconnected from the psyc service.
859 * @param stop_cls
860 * Closure for @a part_cb.
861 */
862void
863GNUNET_PSYC_master_stop (struct GNUNET_PSYC_Master *master,
864 int keep_active,
865 GNUNET_ContinuationCallback stop_cb,
866 void *stop_cls);
867
868
869/**
870 * Handle for a PSYC channel slave.
871 */
872struct GNUNET_PSYC_Slave;
873
874
875/**
876 * Function called after the slave connected to the PSYC service.
877 *
878 * Also called when reconnected to the service
879 * after the connection closed unexpectedly.
880 *
881 * @param cls
882 * Closure.
883 * @param result
884 * #GNUNET_YES if there were already messages sent to the channel,
885 * #GNUNET_NO if the message history is empty,
886 * #GNUNET_SYSERR on error.
887 * @param max_message_id
888 * Last message ID sent to the channel.
889 */
890typedef void
891(*GNUNET_PSYC_SlaveConnectCallback) (void *cls, int result,
892 uint64_t max_message_id);
893
894
895/**
896 * Method called to inform about the decision in response to a join request.
897 *
898 * If @a is_admitted is not #GNUNET_YES, then sending messages to the channel is
899 * not possible, but earlier history can be still queried.
900 *
901 * @param cls Closure.
902 * @param is_admitted #GNUNET_YES or #GNUNET_NO or #GNUNET_SYSERR
903 * @param join_msg Application-dependent join message from the origin.
904 */
905typedef void
906(*GNUNET_PSYC_JoinDecisionCallback) (void *cls,
907 const struct GNUNET_PSYC_JoinDecisionMessage *dcsn,
908 int is_admitted,
909 const struct GNUNET_PSYC_Message *join_msg);
910
911/**
912 * Flags for GNUNET_PSYC_slave_join()
913 */
914enum GNUNET_PSYC_SlaveJoinFlags
915{
916 GNUNET_PSYC_SLAVE_JOIN_NONE = 0,
917
918 /**
919 * Local join for history access, no network connection is established.
920 */
921 GNUNET_PSYC_SLAVE_JOIN_LOCAL = 1,
922};
923
924
925/**
926 * Join a PSYC channel.
927 *
928 * The entity joining is always the local peer. The user must immediately use
929 * the GNUNET_PSYC_slave_transmit() functions to transmit a @e join_msg to the
930 * channel; if the join request succeeds, the channel state (and @e recent
931 * method calls) will be replayed to the joining member. There is no explicit
932 * notification on failure (as the channel may simply take days to approve,
933 * and disapproval is simply being ignored).
934 *
935 * @param cfg
936 * Configuration to use.
937 * @param channel_pub_key
938 * ECC public key that identifies the channel we wish to join.
939 * @param slave_pub_key
940 * ECC private-public key pair that identifies the slave, and
941 * used by multicast to sign the join request and subsequent unicast
942 * requests sent to the master.
943 * @param flags
944 * Join flags.
945 * @param origin
946 * Peer identity of the origin.
947 * @param relay_count
948 * Number of peers in the @a relays array.
949 * @param relays
950 * Peer identities of members of the multicast group, which serve
951 * as relays and used to join the group at.
952 * @param message_cb
953 * Function to invoke on message fragments received from the channel.
954 * @param message_part_cb
955 * Function to invoke on message parts received from the channel.
956 * @param slave_connect_cb
957 * Function invoked once we have connected to the PSYC service.
958 * @param join_decision_cb
959 * Function invoked once we have received a join decision.
960 * @param cls
961 * Closure for @a message_cb and @a slave_joined_cb.
962 * @param join_msg
963 * Join message.
964 *
965 * @return Handle for the slave, NULL on error.
966 */
967struct GNUNET_PSYC_Slave *
968GNUNET_PSYC_slave_join (const struct GNUNET_CONFIGURATION_Handle *cfg,
969 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_pub_key,
970 const struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_pub_key,
971 enum GNUNET_PSYC_SlaveJoinFlags flags,
972 const struct GNUNET_PeerIdentity *origin,
973 uint32_t relay_count,
974 const struct GNUNET_PeerIdentity *relays,
975 GNUNET_PSYC_MessageCallback message_cb,
976 GNUNET_PSYC_MessagePartCallback message_part_cb,
977 GNUNET_PSYC_SlaveConnectCallback slave_connect_cb,
978 GNUNET_PSYC_JoinDecisionCallback join_decision_cb,
979 void *cls,
980 const struct GNUNET_PSYC_Message *join_msg);
981
982
983/**
984 * Part a PSYC channel.
985 *
986 * Will terminate the connection to the PSYC service. Polite clients should
987 * first explicitly send a part request (via GNUNET_PSYC_slave_transmit()).
988 *
989 * @param slave
990 * Slave handle.
991 * @param keep_active
992 * Keep place active after last application disconnected.
993 * @param part_cb
994 * Function called after the slave parted the channel
995 * and disconnected from the psyc service.
996 * @param part_cls
997 * Closure for @a part_cb.
998 */
999void
1000GNUNET_PSYC_slave_part (struct GNUNET_PSYC_Slave *slave,
1001 int keep_active,
1002 GNUNET_ContinuationCallback part_cb,
1003 void *part_cls);
1004
1005
1006/**
1007 * Flags for transmitting messages to the channel master by a slave.
1008 */
1009enum GNUNET_PSYC_SlaveTransmitFlags
1010{
1011 GNUNET_PSYC_SLAVE_TRANSMIT_NONE = 0
1012};
1013
1014
1015/**
1016 * Handle for a pending PSYC transmission operation.
1017 */
1018struct GNUNET_PSYC_SlaveTransmitHandle;
1019
1020
1021/**
1022 * Request a message to be sent to the channel master.
1023 *
1024 * @param slave Slave handle.
1025 * @param method_name Which (PSYC) method should be invoked (on host).
1026 * @param notify_mod Function to call to obtain modifiers.
1027 * @param notify_data Function to call to obtain fragments of the data.
1028 * @param notify_cls Closure for @a notify.
1029 * @param flags Flags for the message being transmitted.
1030 * @return Transmission handle, NULL on error (i.e. more than one request queued).
1031 */
1032struct GNUNET_PSYC_SlaveTransmitHandle *
1033GNUNET_PSYC_slave_transmit (struct GNUNET_PSYC_Slave *slave,
1034 const char *method_name,
1035 GNUNET_PSYC_TransmitNotifyModifier notify_mod,
1036 GNUNET_PSYC_TransmitNotifyData notify_data,
1037 void *notify_cls,
1038 enum GNUNET_PSYC_SlaveTransmitFlags flags);
1039
1040
1041/**
1042 * Resume transmission to the master.
1043 *
1044 * @param th Handle of the request that is being resumed.
1045 */
1046void
1047GNUNET_PSYC_slave_transmit_resume (struct GNUNET_PSYC_SlaveTransmitHandle *th);
1048
1049
1050/**
1051 * Abort transmission request to master.
1052 *
1053 * @param th Handle of the request that is being aborted.
1054 */
1055void
1056GNUNET_PSYC_slave_transmit_cancel (struct GNUNET_PSYC_SlaveTransmitHandle *th);
1057
1058
1059/**
1060 * Handle to access PSYC channel operations for both the master and slaves.
1061 */
1062struct GNUNET_PSYC_Channel;
1063
1064
1065/**
1066 * Convert a channel @a master to a @e channel handle to access the @e channel
1067 * APIs.
1068 *
1069 * @param master Channel master handle.
1070 * @return Channel handle, valid for as long as @a master is valid.
1071 */
1072struct GNUNET_PSYC_Channel *
1073GNUNET_PSYC_master_get_channel (struct GNUNET_PSYC_Master *master);
1074
1075
1076/**
1077 * Convert @a slave to a @e channel handle to access the @e channel APIs.
1078 *
1079 * @param slave Slave handle.
1080 * @return Channel handle, valid for as long as @a slave is valid.
1081 */
1082struct GNUNET_PSYC_Channel *
1083GNUNET_PSYC_slave_get_channel (struct GNUNET_PSYC_Slave *slave);
1084
1085
1086/**
1087 * Add a slave to the channel's membership list.
1088 *
1089 * Note that this will NOT generate any PSYC traffic, it will merely update the
1090 * local database to modify how we react to <em>membership test</em> queries.
1091 * The channel master still needs to explicitly transmit a @e join message to
1092 * notify other channel members and they then also must still call this function
1093 * in their respective methods handling the @e join message. This way, how @e
1094 * join and @e part operations are exactly implemented is still up to the
1095 * application; for example, there might be a @e part_all method to kick out
1096 * everyone.
1097 *
1098 * Note that channel slaves are explicitly trusted to execute such methods
1099 * correctly; not doing so correctly will result in either denying other slaves
1100 * access or offering access to channel data to non-members.
1101 *
1102 * @param channel
1103 * Channel handle.
1104 * @param slave_pub_key
1105 * Identity of channel slave to add.
1106 * @param announced_at
1107 * ID of the message that announced the membership change.
1108 * @param effective_since
1109 * Addition of slave is in effect since this message ID.
1110 * @param result_cb
1111 * Function to call with the result of the operation.
1112 * The @e result_code argument is #GNUNET_OK on success, or
1113 * #GNUNET_SYSERR on error. In case of an error, the @e data argument
1114 * can contain an optional error message.
1115 * @param cls
1116 * Closure for @a result_cb.
1117 */
1118void
1119GNUNET_PSYC_channel_slave_add (struct GNUNET_PSYC_Channel *channel,
1120 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key,
1121 uint64_t announced_at,
1122 uint64_t effective_since,
1123 GNUNET_ResultCallback result_cb,
1124 void *cls);
1125
1126
1127/**
1128 * Remove a slave from the channel's membership list.
1129 *
1130 * Note that this will NOT generate any PSYC traffic, it will merely update the
1131 * local database to modify how we react to <em>membership test</em> queries.
1132 * The channel master still needs to explicitly transmit a @e part message to
1133 * notify other channel members and they then also must still call this function
1134 * in their respective methods handling the @e part message. This way, how
1135 * @e join and @e part operations are exactly implemented is still up to the
1136 * application; for example, there might be a @e part_all message to kick out
1137 * everyone.
1138 *
1139 * Note that channel members are explicitly trusted to perform these
1140 * operations correctly; not doing so correctly will result in either
1141 * denying members access or offering access to channel data to
1142 * non-members.
1143 *
1144 * @param channel
1145 * Channel handle.
1146 * @param slave_pub_key
1147 * Identity of channel slave to remove.
1148 * @param announced_at
1149 * ID of the message that announced the membership change.
1150 * @param result_cb
1151 * Function to call with the result of the operation.
1152 * The @e result_code argument is #GNUNET_OK on success, or
1153 * #GNUNET_SYSERR on error. In case of an error, the @e data argument
1154 * can contain an optional error message.
1155 * @param cls
1156 * Closure for @a result_cb.
1157 */
1158void
1159GNUNET_PSYC_channel_slave_remove (struct GNUNET_PSYC_Channel *channel,
1160 const struct GNUNET_CRYPTO_EcdsaPublicKey
1161 *slave_pub_key,
1162 uint64_t announced_at,
1163 GNUNET_ResultCallback result_cb,
1164 void *cls);
1165
1166
1167/**
1168 * History request handle.
1169 */
1170struct GNUNET_PSYC_HistoryRequest;
1171
1172
1173/**
1174 * Request to replay a part of the message history of the channel.
1175 *
1176 * Historic messages (but NOT the state at the time) will be replayed (given to
1177 * the normal method handlers) if available and if access is permitted.
1178 *
1179 * @param channel
1180 * Which channel should be replayed?
1181 * @param start_message_id
1182 * Earliest interesting point in history.
1183 * @param end_message_id
1184 * Last (inclusive) interesting point in history.
1185 * @param method_prefix
1186 * Retrieve only messages with a matching method prefix.
1187 * @param flags
1188 * OR'ed enum GNUNET_PSYC_HistoryReplayFlags
1189 * @param result_cb
1190 * Function to call when the requested history has been fully replayed.
1191 * Once this function has been called, the client must not call
1192 * GNUNET_PSYC_channel_history_replay_cancel() anymore.
1193 * @param cls
1194 * Closure for the callbacks.
1195 *
1196 * @return Handle to cancel history replay operation.
1197 */
1198struct GNUNET_PSYC_HistoryRequest *
1199GNUNET_PSYC_channel_history_replay (struct GNUNET_PSYC_Channel *channel,
1200 uint64_t start_message_id,
1201 uint64_t end_message_id,
1202 const char *method_prefix,
1203 uint32_t flags,
1204 GNUNET_PSYC_MessageCallback message_cb,
1205 GNUNET_PSYC_MessagePartCallback message_part_cb,
1206 GNUNET_ResultCallback result_cb,
1207 void *cls);
1208
1209
1210/**
1211 * Request to replay the latest messages from the message history of the channel.
1212 *
1213 * Historic messages (but NOT the state at the time) will be replayed (given to
1214 * the normal method handlers) if available and if access is permitted.
1215 *
1216 * @param channel
1217 * Which channel should be replayed?
1218 * @param message_limit
1219 * Maximum number of messages to replay.
1220 * @param flags
1221 * OR'ed enum GNUNET_PSYC_HistoryReplayFlags
1222 * @param finish_cb
1223 * Function to call when the requested history has been fully replayed
1224 * (counting message IDs might not suffice, as some messages might be
1225 * secret and thus the listener would not know the story is finished
1226 * without being told explicitly)o once this function has been called, the
1227 * client must not call GNUNET_PSYC_channel_history_replay_cancel() anymore.
1228 * @param cls
1229 * Closure for the callbacks.
1230 *
1231 * @return Handle to cancel history replay operation.
1232 */
1233struct GNUNET_PSYC_HistoryRequest *
1234GNUNET_PSYC_channel_history_replay_latest (struct GNUNET_PSYC_Channel *channel,
1235 uint64_t message_limit,
1236 const char *method_prefix,
1237 uint32_t flags,
1238 GNUNET_PSYC_MessageCallback message_cb,
1239 GNUNET_PSYC_MessagePartCallback message_part_cb,
1240 GNUNET_ResultCallback result_cb,
1241 void *cls);
1242
1243
1244void
1245GNUNET_PSYC_channel_history_replay_cancel (struct GNUNET_PSYC_Channel *channel,
1246 struct GNUNET_PSYC_HistoryRequest *hr);
1247
1248
1249/**
1250 * Function called to inform a member about stored state values for a channel.
1251 *
1252 * If @a full_value_size > value_size then this function is called multiple
1253 * times until the whole value arrived.
1254 *
1255 * @param cls
1256 * Closure.
1257 * @param name
1258 * Name of the state variable.
1259 * NULL if there are no more state variables to be returned.
1260 * @param value
1261 * Value of the state variable.
1262 * @param value_size
1263 * Number of bytes in @a value.
1264 * @param full_value_size
1265 * Number of bytes in the full value, including continuations.
1266 * Only set for the first part of a variable,
1267 * in case of a continuation it is 0.
1268 */
1269typedef void
1270(*GNUNET_PSYC_StateVarCallback) (void *cls,
1271 const struct GNUNET_MessageHeader *mod,
1272 const char *name,
1273 const void *value,
1274 uint32_t value_size,
1275 uint32_t full_value_size);
1276
1277
1278/**
1279 * State request handle.
1280 */
1281struct GNUNET_PSYC_StateRequest;
1282
1283
1284/**
1285 * Retrieve the best matching channel state variable.
1286 *
1287 * If the requested variable name is not present in the state, the nearest
1288 * less-specific name is matched; for example, requesting "_a_b" will match "_a"
1289 * if "_a_b" does not exist.
1290 *
1291 * @param channel
1292 * Channel handle.
1293 * @param full_name
1294 * Full name of the requested variable.
1295 * The actual variable returned might have a shorter name.
1296 * @param var_cb
1297 * Function called once when a matching state variable is found.
1298 * Not called if there's no matching state variable.
1299 * @param result_cb
1300 * Function called after the operation finished.
1301 * (i.e. all state variables have been returned via @a state_cb)
1302 * @param cls
1303 * Closure for the callbacks.
1304 */
1305struct GNUNET_PSYC_StateRequest *
1306GNUNET_PSYC_channel_state_get (struct GNUNET_PSYC_Channel *channel,
1307 const char *full_name,
1308 GNUNET_PSYC_StateVarCallback var_cb,
1309 GNUNET_ResultCallback result_cb,
1310 void *cls);
1311
1312
1313/**
1314 * Return all channel state variables whose name matches a given prefix.
1315 *
1316 * A name matches if it starts with the given @a name_prefix, thus requesting
1317 * the empty prefix ("") will match all values; requesting "_a_b" will also
1318 * return values stored under "_a_b_c".
1319 *
1320 * The @a state_cb is invoked on all matching state variables asynchronously, as
1321 * the state is stored in and retrieved from the PSYCstore,
1322 *
1323 * @param channel
1324 * Channel handle.
1325 * @param name_prefix
1326 * Prefix of the state variable name to match.
1327 * @param var_cb
1328 * Function called once when a matching state variable is found.
1329 * Not called if there's no matching state variable.
1330 * @param result_cb
1331 * Function called after the operation finished.
1332 * (i.e. all state variables have been returned via @a state_cb)
1333 * @param cls
1334 * Closure for the callbacks.
1335 */
1336struct GNUNET_PSYC_StateRequest *
1337GNUNET_PSYC_channel_state_get_prefix (struct GNUNET_PSYC_Channel *channel,
1338 const char *name_prefix,
1339 GNUNET_PSYC_StateVarCallback var_cb,
1340 GNUNET_ResultCallback result_cb,
1341 void *cls);
1342
1343/**
1344 * Cancel a state request operation.
1345 *
1346 * @param sr
1347 * Handle for the operation to cancel.
1348 */
1349void
1350GNUNET_PSYC_channel_state_get_cancel (struct GNUNET_PSYC_StateRequest *sr);
1351
1352
1353
1354#if 0 /* keep Emacsens' auto-indent happy */
1355{
1356#endif
1357#ifdef __cplusplus
1358}
1359#endif
1360
1361/* ifndef GNUNET_PSYC_SERVICE_H */
1362#endif
1363
1364/** @} */ /* 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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19*/
20
21/**
22 * @author Gabor X Toth
23 * @author Christian Grothoff
24 *
25 * @file
26 * PSYC Slicer library
27 *
28 * @defgroup psyc-util-slicer PSYC Utilities library: Slicer
29 * Try-and-slice processing of PSYC method names and environment.
30 * @{
31 */
32
33#ifndef GNUNET_PSYC_SLICER_H
34#define GNUNET_PSYC_SLICER_H
35
36
37#ifdef __cplusplus
38extern "C"
39{
40#if 0 /* keep Emacsens' auto-indent happy */
41}
42#endif
43#endif
44
45#include "gnunet_util_lib.h"
46
47
48/**
49 * Handle to an implementation of try-and-slice.
50 */
51struct GNUNET_PSYC_Slicer;
52
53
54/**
55 * Function called upon receiving a message indicating a call to a @e method.
56 *
57 * This function is called one or more times for each message until all data
58 * fragments arrive from the network.
59 *
60 * @param cls
61 * Closure.
62 * @param msg
63 * Message part, as it arrived from the network.
64 * @param message_id
65 * Message counter, monotonically increasing from 1.
66 * @param flags
67 * OR'ed GNUNET_PSYC_MessageFlags
68 * @param fragment_offset
69 * Multicast message fragment offset.
70 * @param tmit_flags
71 * OR'ed GNUNET_PSYC_MasterTransmitFlags
72 * @param nym
73 * The sender of the message.
74 * Can be NULL if the message is not connected to a pseudonym.
75 * @param method_name
76 * Original method name from PSYC.
77 * May be more specific than the registered method name due to
78 * try-and-slice matching.
79 */
80typedef void
81(*GNUNET_PSYC_MethodCallback) (void *cls,
82 const struct GNUNET_PSYC_MessageHeader *msg,
83 const struct GNUNET_PSYC_MessageMethod *meth,
84 uint64_t message_id,
85 const char *method_name);
86
87
88/**
89 * Function called upon receiving a modifier of a message.
90 *
91 * @param cls
92 * Closure.
93 * @param message_id
94 * Message ID this data fragment belongs to.
95 * @param flags
96 * OR'ed GNUNET_PSYC_MessageFlags
97 * @param fragment_offset
98 * Multicast message fragment offset.
99 * @param msg
100 * Message part, as it arrived from the network.
101 * @param oper
102 * Operation to perform.
103 * 0 in case of a modifier continuation.
104 * @param name
105 * Name of the modifier.
106 * NULL in case of a modifier continuation.
107 * @param value
108 * Value of the modifier.
109 * @param value_size
110 * Size of @value.
111 */
112typedef void
113(*GNUNET_PSYC_ModifierCallback) (void *cls,
114 const struct GNUNET_PSYC_MessageHeader *msg,
115 const struct GNUNET_MessageHeader *pmsg,
116 uint64_t message_id,
117 enum GNUNET_PSYC_Operator oper,
118 const char *name,
119 const void *value,
120 uint16_t value_size,
121 uint16_t full_value_size);
122
123
124/**
125 * Function called upon receiving a data fragment of a message.
126 *
127 * @param cls
128 * Closure.
129 * @param msg
130 * Message part, as it arrived from the network.
131 * @param message_id
132 * Message ID this data fragment belongs to.
133 * @param flags
134 * OR'ed GNUNET_PSYC_MessageFlags
135 * @param fragment_offset
136 * Multicast message fragment offset.
137 * @param data
138 * Data stream given to the method.
139 * @param data_size
140 * Number of bytes in @a data.
141 * @param end
142 * End of message?
143 * #GNUNET_NO if there are further fragments,
144 * #GNUNET_YES if this is the last fragment,
145 * #GNUNET_SYSERR indicates the message was cancelled by the sender.
146 */
147typedef void
148(*GNUNET_PSYC_DataCallback) (void *cls,
149 const struct GNUNET_PSYC_MessageHeader *msg,
150 const struct GNUNET_MessageHeader *pmsg,
151 uint64_t message_id,
152 const void *data,
153 uint16_t data_size);
154
155
156/**
157 * End of message.
158 *
159 * @param cls
160 * Closure.
161 * @param msg
162 * Message part, as it arrived from the network.
163 * @param message_id
164 * Message ID this data fragment belongs to.
165 * @param flags
166 * OR'ed GNUNET_PSYC_MessageFlags
167 * @param fragment_offset
168 * Multicast message fragment offset.
169 * @param cancelled
170 * #GNUNET_YES if the message was cancelled,
171 * #GNUNET_NO if the message is complete.
172 */
173typedef void
174(*GNUNET_PSYC_EndOfMessageCallback) (void *cls,
175 const struct GNUNET_PSYC_MessageHeader *msg,
176 const struct GNUNET_MessageHeader *pmsg,
177 uint64_t message_id,
178 uint8_t is_cancelled);
179
180
181/**
182 * Create a try-and-slice instance.
183 *
184 * A slicer processes incoming messages and notifies callbacks about matching
185 * methods or modifiers encountered.
186 *
187 * @return A new try-and-slice construct.
188 */
189struct GNUNET_PSYC_Slicer *
190GNUNET_PSYC_slicer_create (void);
191
192
193/**
194 * Add a method to the try-and-slice instance.
195 *
196 * The callbacks are called for messages with a matching @a method_name prefix.
197 *
198 * @param slicer
199 * The try-and-slice instance to extend.
200 * @param method_name
201 * Name of the given method, use empty string to match all.
202 * @param method_cb
203 * Method handler invoked upon a matching message.
204 * @param modifier_cb
205 * Modifier handler, invoked after @a method_cb
206 * for each modifier in the message.
207 * @param data_cb
208 * Data handler, invoked after @a modifier_cb for each data fragment.
209 * @param eom_cb
210 * Invoked upon reaching the end of a matching message.
211 * @param cls
212 * Closure for the callbacks.
213 */
214void
215GNUNET_PSYC_slicer_method_add (struct GNUNET_PSYC_Slicer *slicer,
216 const char *method_name,
217 GNUNET_PSYC_MessageCallback msg_cb,
218 GNUNET_PSYC_MethodCallback method_cb,
219 GNUNET_PSYC_ModifierCallback modifier_cb,
220 GNUNET_PSYC_DataCallback data_cb,
221 GNUNET_PSYC_EndOfMessageCallback eom_cb,
222 void *cls);
223
224/**
225 * Remove a registered method from the try-and-slice instance.
226 *
227 * Removes one matching handler registered with the given
228 * @a method_name and callbacks.
229 *
230 * @param slicer
231 * The try-and-slice instance.
232 * @param method_name
233 * Name of the method to remove.
234 * @param method_cb
235 * Only remove matching method handler, or NULL.
236 * @param modifier_cb
237 * Only remove matching modifier handler, or NULL.
238 * @param data_cb
239 * Only remove matching data handler, or NULL.
240 * @param eom_cb
241 * Only remove matching End of Message handler, or NULL.
242 *
243 * @return #GNUNET_OK if a method handler was removed,
244 * #GNUNET_NO if no handler matched the given method name and callbacks.
245 */
246int
247GNUNET_PSYC_slicer_method_remove (struct GNUNET_PSYC_Slicer *slicer,
248 const char *method_name,
249 GNUNET_PSYC_MessageCallback msg_cb,
250 GNUNET_PSYC_MethodCallback method_cb,
251 GNUNET_PSYC_ModifierCallback modifier_cb,
252 GNUNET_PSYC_DataCallback data_cb,
253 GNUNET_PSYC_EndOfMessageCallback eom_cb);
254
255
256/**
257 * Watch a place for changed objects.
258 *
259 * @param slicer
260 * The try-and-slice instance.
261 * @param object_filter
262 * Object prefix to match.
263 * @param modifier_cb
264 * Function to call when encountering a state modifier.
265 * @param cls
266 * Closure for callback.
267 */
268void
269GNUNET_PSYC_slicer_modifier_add (struct GNUNET_PSYC_Slicer *slicer,
270 const char *object_filter,
271 GNUNET_PSYC_ModifierCallback modifier_cb,
272 void *cls);
273
274
275/**
276 * Remove a registered modifier from the try-and-slice instance.
277 *
278 * Removes one matching handler registered with the given
279 * @a object_filter and callback.
280 *
281 * @param slicer
282 * The try-and-slice instance.
283 * @param object_filter
284 * Object prefix to match.
285 * @param modifier_cb
286 * Function to call when encountering a state modifier changes.
287 */
288int
289GNUNET_PSYC_slicer_modifier_remove (struct GNUNET_PSYC_Slicer *slicer,
290 const char *object_filter,
291 GNUNET_PSYC_ModifierCallback modifier_cb);
292
293
294/**
295 * Process an incoming message and call matching handlers.
296 *
297 * @param slicer
298 * The slicer to use.
299 * @param msg
300 * The message as it arrived from the network.
301 */
302void
303GNUNET_PSYC_slicer_message (struct GNUNET_PSYC_Slicer *slicer,
304 const struct GNUNET_PSYC_MessageHeader *msg);
305
306
307/**
308 * Process an incoming message part and call matching handlers.
309 *
310 * @param slicer
311 * The slicer to use.
312 * @param message_id
313 * ID of the message.
314 * @param flags
315 * Flags for the message.
316 * @see enum GNUNET_PSYC_MessageFlags
317 * @param fragment offset
318 * Fragment offset of the message.
319 * @param msg
320 * The message part as it arrived from the network.
321 */
322void
323GNUNET_PSYC_slicer_message_part (struct GNUNET_PSYC_Slicer *slicer,
324 const struct GNUNET_PSYC_MessageHeader *msg,
325 const struct GNUNET_MessageHeader *pmsg);
326
327
328/**
329 * Remove all registered method handlers.
330 *
331 * @param slicer
332 * Slicer to clear.
333 */
334void
335GNUNET_PSYC_slicer_method_clear (struct GNUNET_PSYC_Slicer *slicer);
336
337
338/**
339 * Remove all registered modifier handlers.
340 *
341 * @param slicer
342 * Slicer to clear.
343 */
344void
345GNUNET_PSYC_slicer_modifier_clear (struct GNUNET_PSYC_Slicer *slicer);
346
347
348/**
349 * Remove all registered method & modifier handlers.
350 *
351 * @param slicer
352 * Slicer to clear.
353 */
354void
355GNUNET_PSYC_slicer_clear (struct GNUNET_PSYC_Slicer *slicer);
356
357
358/**
359 * Destroy a given try-and-slice instance.
360 *
361 * @param slicer
362 * Slicer to destroy
363 */
364void
365GNUNET_PSYC_slicer_destroy (struct GNUNET_PSYC_Slicer *slicer);
366
367
368#if 0 /* keep Emacsens' auto-indent happy */
369{
370#endif
371#ifdef __cplusplus
372}
373#endif
374
375/* ifndef GNUNET_PSYC_SLICER_H */
376#endif
377
378/** @} */ /* 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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19*/
20
21/**
22 * @author Gabor X Toth
23 *
24 * @file
25 * PSYC utilities: messages, environment, slicer
26 */
27
28#ifndef GNUNET_PSYC_UTIL_LIB_H
29#define GNUNET_PSYC_UTIL_LIB_H
30
31#ifdef __cplusplus
32extern "C"
33{
34#if 0 /* keep Emacsens' auto-indent happy */
35}
36#endif
37#endif
38
39
40#include "gnunet_psyc_env.h"
41#include "gnunet_psyc_message.h"
42#include "gnunet_psyc_slicer.h"
43
44
45#if 0 /* keep Emacsens' auto-indent happy */
46{
47#endif
48#ifdef __cplusplus
49}
50#endif
51
52/* ifndef GNUNET_PSYC_UTIL_LIB_H */
53#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 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19*/
20
21/**
22 * @author Gabor X Toth
23 *
24 * @file
25 * Plugin API for the PSYCstore database backend
26 *
27 * @defgroup psycstore-plugin PSYC Store plugin API
28 * Plugin API for the PSYC Store database backend
29 * @{
30 */
31#ifndef GNUNET_PSYCSTORE_PLUGIN_H
32#define GNUNET_PSYCSTORE_PLUGIN_H
33
34#include "gnunet_util_lib.h"
35#include "gnunet_psycstore_service.h"
36
37#ifdef __cplusplus
38extern "C"
39{
40#if 0 /* keep Emacsens' auto-indent happy */
41}
42#endif
43#endif
44
45
46/**
47 * Struct returned by the initialization function of the plugin.
48 */
49struct GNUNET_PSYCSTORE_PluginFunctions
50{
51
52 /**
53 * Closure to pass to all plugin functions.
54 */
55 void *cls;
56
57 /**
58 * Store join/leave events for a PSYC channel in order to be able to answer
59 * membership test queries later.
60 *
61 * @see GNUNET_PSYCSTORE_membership_store()
62 *
63 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
64 */
65 int
66 (*membership_store) (void *cls,
67 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
68 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
69 int did_join,
70 uint64_t announced_at,
71 uint64_t effective_since,
72 uint64_t group_generation);
73
74 /**
75 * Test if a member was admitted to the channel at the given message ID.
76 *
77 * @see GNUNET_PSYCSTORE_membership_test()
78 *
79 * @return #GNUNET_YES if the member was admitted, #GNUNET_NO if not,
80 * #GNUNET_SYSERR if there was en error.
81 */
82 int
83 (*membership_test) (void *cls,
84 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
85 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
86 uint64_t message_id);
87
88 /**
89 * Store a message fragment sent to a channel.
90 *
91 * @see GNUNET_PSYCSTORE_fragment_store()
92 *
93 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
94 */
95 int
96 (*fragment_store) (void *cls,
97 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
98 const struct GNUNET_MULTICAST_MessageHeader *message,
99 uint32_t psycstore_flags);
100
101 /**
102 * Set additional flags for a given message.
103 *
104 * They are OR'd with any existing flags set.
105 *
106 * @param cls Closure.
107 * @param channel_key Public key of the channel.
108 * @param message_id ID of the message.
109 * @param psycstore_flags OR'd GNUNET_PSYCSTORE_MessageFlags.
110 *
111 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
112 */
113 int
114 (*message_add_flags) (void *cls,
115 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
116 uint64_t message_id,
117 uint32_t psycstore_flags);
118
119 /**
120 * Retrieve a message fragment range by fragment ID.
121 *
122 * @see GNUNET_PSYCSTORE_fragment_get()
123 *
124 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
125 */
126 int
127 (*fragment_get) (void *cls,
128 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
129 uint64_t first_fragment_id,
130 uint64_t last_fragment_id,
131 uint64_t *returned_fragments,
132 GNUNET_PSYCSTORE_FragmentCallback cb,
133 void *cb_cls);
134
135 /**
136 * Retrieve latest message fragments.
137 *
138 * @see GNUNET_PSYCSTORE_fragment_get()
139 *
140 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
141 */
142 int
143 (*fragment_get_latest) (void *cls,
144 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
145 uint64_t fragment_limit,
146 uint64_t *returned_fragments,
147 GNUNET_PSYCSTORE_FragmentCallback cb,
148 void *cb_cls);
149
150 /**
151 * Retrieve all fragments of a message ID range.
152 *
153 * @see GNUNET_PSYCSTORE_message_get()
154 *
155 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
156 */
157 int
158 (*message_get) (void *cls,
159 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
160 uint64_t first_fragment_id,
161 uint64_t last_fragment_id,
162 uint64_t fragment_limit,
163 uint64_t *returned_fragments,
164 GNUNET_PSYCSTORE_FragmentCallback cb,
165 void *cb_cls);
166
167 /**
168 * Retrieve all fragments of the latest messages.
169 *
170 * @see GNUNET_PSYCSTORE_message_get()
171 *
172 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
173 */
174 int
175 (*message_get_latest) (void *cls,
176 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
177 uint64_t fragment_limit,
178 uint64_t *returned_fragments,
179 GNUNET_PSYCSTORE_FragmentCallback cb,
180 void *cb_cls);
181
182 /**
183 * Retrieve a fragment of message specified by its message ID and fragment
184 * offset.
185 *
186 * @see GNUNET_PSYCSTORE_message_get_fragment()
187 *
188 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
189 */
190 int
191 (*message_get_fragment) (void *cls,
192 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
193 uint64_t message_id,
194 uint64_t fragment_offset,
195 GNUNET_PSYCSTORE_FragmentCallback cb,
196 void *cb_cls);
197
198 /**
199 * Retrieve the max. values of message counters for a channel.
200 *
201 * @see GNUNET_PSYCSTORE_counters_get()
202 *
203 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
204 */
205 int
206 (*counters_message_get) (void *cls,
207 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
208 uint64_t *max_fragment_id,
209 uint64_t *max_message_id,
210 uint64_t *max_group_generation);
211
212 /**
213 * Retrieve the max. values of state counters for a channel.
214 *
215 * @see GNUNET_PSYCSTORE_counters_get()
216 *
217 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
218 */
219 int
220 (*counters_state_get) (void *cls,
221 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
222 uint64_t *max_state_message_id);
223
224
225 /**
226 * Begin modifying current state.
227 *
228 * @see GNUNET_PSYCSTORE_state_modify()
229 *
230 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
231 */
232 int
233 (*state_modify_begin) (void *cls,
234 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
235 uint64_t message_id, uint64_t state_delta);
236
237 /**
238 * Set the current value of a state variable.
239 *
240 * The state modification process is started with state_modify_begin(),
241 * which is followed by one or more calls to this function,
242 * and finished with state_modify_end().
243 *
244 * @see GNUNET_PSYCSTORE_state_modify()
245 *
246 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
247 */
248 int
249 (*state_modify_op) (void *cls,
250 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
251 enum GNUNET_PSYC_Operator op,
252 const char *name, const void *value, size_t value_size);
253
254
255 /**
256 * End modifying current state.
257 *
258 * @see GNUNET_PSYCSTORE_state_modify()
259 *
260 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
261 */
262 int
263 (*state_modify_end) (void *cls,
264 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
265 uint64_t message_id);
266
267
268 /**
269 * Begin synchronizing state.
270 *
271 * @see GNUNET_PSYCSTORE_state_sync()
272 *
273 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
274 */
275 int
276 (*state_sync_begin) (void *cls,
277 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key);
278
279 /**
280 * Assign value of a state variable while synchronizing state.
281 *
282 * The state synchronization process is started with state_sync_begin(),
283 * which is followed by one or more calls to this function,
284 * and finished using state_sync_end().
285 *
286 * @see GNUNET_PSYCSTORE_state_sync()
287 *
288 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
289 */
290 int
291 (*state_sync_assign) (void *cls,
292 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
293 const char *name, const void *value, size_t value_size);
294
295
296 /**
297 * End synchronizing state.
298 *
299 * @see GNUNET_PSYCSTORE_state_sync()
300 *
301 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
302 */
303 int
304 (*state_sync_end) (void *cls,
305 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
306 uint64_t max_state_message_id,
307 uint64_t state_hash_message_id);
308
309
310 /**
311 * Reset the state of a channel.
312 *
313 * Delete all state variables stored for the given channel.
314 *
315 * @see GNUNET_PSYCSTORE_state_reset()
316 *
317 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
318 */
319 int
320 (*state_reset) (void *cls,
321 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key);
322
323 /**
324 * Update signed state values from the current ones.
325 *
326 * Sets value_signed = value_current for each variable for the given channel.
327 */
328 int
329 (*state_update_signed) (void *cls,
330 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key);
331
332
333 /**
334 * Retrieve a state variable by name (exact match).
335 *
336 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
337 */
338 int
339 (*state_get) (void *cls,
340 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
341 const char *name,
342 GNUNET_PSYCSTORE_StateCallback cb,
343 void *cb_cls);
344
345 /**
346 * Retrieve all state variables for a channel with the given prefix.
347 *
348 * @see GNUNET_PSYCSTORE_state_get_prefix()
349 *
350 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
351 */
352 int
353 (*state_get_prefix) (void *cls,
354 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
355 const char *name,
356 GNUNET_PSYCSTORE_StateCallback cb,
357 void *cb_cls);
358
359
360 /**
361 * Retrieve all signed state variables for a channel.
362 *
363 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
364 */
365 int
366 (*state_get_signed) (void *cls,
367 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
368 GNUNET_PSYCSTORE_StateCallback cb,
369 void *cb_cls);
370
371};
372
373
374#if 0 /* keep Emacsens' auto-indent happy */
375{
376#endif
377#ifdef __cplusplus
378}
379#endif
380
381#endif
382
383/** @} */ /* 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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19*/
20
21/**
22 * @author Gabor X Toth
23 * @author Christian Grothoff
24 *
25 * @file
26 * PSYCstore service; implements persistent storage for the PSYC service
27 *
28 * @defgroup psycstore PSYC Store service
29 * Persistent storage for the PSYC service.
30 * @{
31 */
32#ifndef GNUNET_PSYCSTORE_SERVICE_H
33#define GNUNET_PSYCSTORE_SERVICE_H
34
35#ifdef __cplusplus
36extern "C"
37{
38#if 0 /* keep Emacsens' auto-indent happy */
39}
40#endif
41#endif
42
43#include "gnunet_util_lib.h"
44#include "gnunet_psyc_util_lib.h"
45#include "gnunet_multicast_service.h"
46#include "gnunet_psyc_service.h"
47
48/**
49 * Version number of GNUnet PSYCstore API.
50 */
51#define GNUNET_PSYCSTORE_VERSION 0x00000000
52
53/**
54 * Membership test failed.
55 */
56#define GNUNET_PSYCSTORE_MEMBERSHIP_TEST_FAILED -2
57
58/**
59 * Flags for stored messages.
60 */
61enum GNUNET_PSYCSTORE_MessageFlags
62{
63 /**
64 * The message contains state modifiers.
65 */
66 GNUNET_PSYCSTORE_MESSAGE_STATE = 1 << 0,
67
68 /**
69 * The state modifiers have been applied to the state store.
70 */
71 GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED = 1 << 1,
72
73 /**
74 * The message contains a state hash.
75 */
76 GNUNET_PSYCSTORE_MESSAGE_STATE_HASH = 1 << 2
77};
78
79
80/**
81 * Handle for a PSYCstore
82 */
83struct GNUNET_PSYCSTORE_Handle;
84
85
86/**
87 * Connect to the PSYCstore service.
88 *
89 * @param cfg Configuration to use.
90 *
91 * @return Handle for the connecton.
92 */
93struct GNUNET_PSYCSTORE_Handle *
94GNUNET_PSYCSTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg);
95
96
97/**
98 * Disconnect from the PSYCstore service.
99 *
100 * @param h Handle for the connection.
101 */
102void
103GNUNET_PSYCSTORE_disconnect (struct GNUNET_PSYCSTORE_Handle *h);
104
105
106/**
107 * Handle for an operation on the PSYCSTORE (useful to cancel the operation).
108 */
109struct GNUNET_PSYCSTORE_OperationHandle;
110
111
112/**
113 * Function called with the result of an asynchronous operation.
114 *
115 * @param cls
116 * Closure.
117 * @param result
118 * Result of the operation.
119 * @param err_msg
120 * Error message, or NULL if there's no error.
121 * @param err_msg_size
122 * Size of @a err_msg
123 */
124typedef void
125(*GNUNET_PSYCSTORE_ResultCallback) (void *cls,
126 int64_t result,
127 const char *err_msg,
128 uint16_t err_msg_size);
129
130
131/**
132 * Store join/leave events for a PSYC channel in order to be able to answer
133 * membership test queries later.
134 *
135 * @param h
136 * Handle for the PSYCstore.
137 * @param channel_key
138 * The channel where the event happened.
139 * @param slave_key
140 * Public key of joining/leaving slave.
141 * @param did_join
142 * #GNUNET_YES on join, #GNUNET_NO on part.
143 * @param announced_at
144 * ID of the message that announced the membership change.
145 * @param effective_since
146 * Message ID this membership change is in effect since.
147 * For joins it is <= announced_at, for parts it is always 0.
148 * @param group_generation
149 * In case of a part, the last group generation the slave has access to.
150 * It has relevance when a larger message have fragments with different
151 * group generations.
152 * @param result_cb
153 * Callback to call with the result of the storage operation.
154 * @param cls
155 * Closure for the callback.
156 *
157 * @return Operation handle that can be used to cancel the operation.
158 */
159struct GNUNET_PSYCSTORE_OperationHandle *
160GNUNET_PSYCSTORE_membership_store (struct GNUNET_PSYCSTORE_Handle *h,
161 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
162 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
163 int did_join,
164 uint64_t announced_at,
165 uint64_t effective_since,
166 uint64_t group_generation,
167 GNUNET_PSYCSTORE_ResultCallback result_cb,
168 void *cls);
169
170
171/**
172 * Test if a member was admitted to the channel at the given message ID.
173 *
174 * This is useful when relaying and replaying messages to check if a particular
175 * slave has access to the message fragment with a given group generation. It
176 * is also used when handling join requests to determine whether the slave is
177 * currently admitted to the channel.
178 *
179 * @param h
180 * Handle for the PSYCstore.
181 * @param channel_key
182 * The channel we are interested in.
183 * @param slave_key
184 * Public key of slave whose membership to check.
185 * @param message_id
186 * Message ID for which to do the membership test.
187 * @param group_generation
188 * Group generation of the fragment of the message to test.
189 * It has relevance if the message consists of multiple fragments with
190 * different group generations.
191 * @param result_cb
192 * Callback to call with the test result.
193 * @param cls
194 * Closure for the callback.
195 *
196 * @return Operation handle that can be used to cancel the operation.
197 */
198struct GNUNET_PSYCSTORE_OperationHandle *
199GNUNET_PSYCSTORE_membership_test (struct GNUNET_PSYCSTORE_Handle *h,
200 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
201 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
202 uint64_t message_id,
203 uint64_t group_generation,
204 GNUNET_PSYCSTORE_ResultCallback result_cb,
205 void *cls);
206
207
208/**
209 * Store a message fragment sent to a channel.
210 *
211 * @param h Handle for the PSYCstore.
212 * @param channel_key The channel the message belongs to.
213 * @param msg Message to store.
214 * @param psycstore_flags Flags indicating whether the PSYC message contains
215 * state modifiers.
216 * @param result_cb Callback to call with the result of the operation.
217 * @param cls Closure for the callback.
218 *
219 * @return Handle that can be used to cancel the operation.
220 */
221struct GNUNET_PSYCSTORE_OperationHandle *
222GNUNET_PSYCSTORE_fragment_store (struct GNUNET_PSYCSTORE_Handle *h,
223 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
224 const struct GNUNET_MULTICAST_MessageHeader *msg,
225 enum GNUNET_PSYCSTORE_MessageFlags psycstore_flags,
226 GNUNET_PSYCSTORE_ResultCallback result_cb,
227 void *cls);
228
229
230/**
231 * Function called with one message fragment, as the result of a
232 * GNUNET_PSYCSTORE_fragment_get() or GNUNET_PSYCSTORE_message_get() call.
233 *
234 * @param cls Closure.
235 * @param message The retrieved message fragment. A NULL value indicates that
236 * there are no more results to be returned.
237 * @param psycstore_flags Flags stored with the message.
238 *
239 * @return #GNUNET_NO to stop calling this callback with further fragments,
240 * #GNUNET_YES to continue.
241 */
242typedef int
243(*GNUNET_PSYCSTORE_FragmentCallback) (void *cls,
244 struct GNUNET_MULTICAST_MessageHeader *message,
245 enum GNUNET_PSYCSTORE_MessageFlags psycstore_flags);
246
247
248/**
249 * Retrieve message fragments by fragment ID range.
250 *
251 * @param h
252 * Handle for the PSYCstore.
253 * @param channel_key
254 * The channel we are interested in.
255 * @param slave_key
256 * The slave requesting the fragment. If not NULL, a membership test is
257 * performed first and the fragment is only returned if the slave has
258 * access to it.
259 * @param first_fragment_id
260 * First fragment ID to retrieve.
261 * Use 0 to get the latest message fragment.
262 * @param last_fragment_id
263 * Last consecutive fragment ID to retrieve.
264 * Use 0 to get the latest message fragment.
265 * @param fragment_cb
266 * Callback to call with the retrieved fragments.
267 * @param result_cb
268 * Callback to call with the result of the operation.
269 * @param cls
270 * Closure for the callbacks.
271 *
272 * @return Handle that can be used to cancel the operation.
273 */
274struct GNUNET_PSYCSTORE_OperationHandle *
275GNUNET_PSYCSTORE_fragment_get (struct GNUNET_PSYCSTORE_Handle *h,
276 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
277 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
278 uint64_t first_message_id,
279 uint64_t last_message_id,
280 GNUNET_PSYCSTORE_FragmentCallback fragment_cb,
281 GNUNET_PSYCSTORE_ResultCallback result_cb,
282 void *cls);
283
284
285/**
286 * Retrieve latest message fragments.
287 *
288 * @param h
289 * Handle for the PSYCstore.
290 * @param channel_key
291 * The channel we are interested in.
292 * @param slave_key
293 * The slave requesting the fragment. If not NULL, a membership test is
294 * performed first and the fragment is only returned if the slave has
295 * access to it.
296 * @param first_fragment_id
297 * First fragment ID to retrieve.
298 * Use 0 to get the latest message fragment.
299 * @param last_fragment_id
300 * Last consecutive fragment ID to retrieve.
301 * Use 0 to get the latest message fragment.
302 * @param fragment_limit
303 * Maximum number of fragments to retrieve.
304 * @param fragment_cb
305 * Callback to call with the retrieved fragments.
306 * @param result_cb
307 * Callback to call with the result of the operation.
308 * @param cls
309 * Closure for the callbacks.
310 *
311 * @return Handle that can be used to cancel the operation.
312 */
313struct GNUNET_PSYCSTORE_OperationHandle *
314GNUNET_PSYCSTORE_fragment_get_latest (struct GNUNET_PSYCSTORE_Handle *h,
315 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
316 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
317 uint64_t fragment_limit,
318 GNUNET_PSYCSTORE_FragmentCallback fragment_cb,
319 GNUNET_PSYCSTORE_ResultCallback result_cb,
320 void *cls);
321
322
323/**
324 * Retrieve all fragments of messages in a message ID range.
325 *
326 * @param h
327 * Handle for the PSYCstore.
328 * @param channel_key
329 * The channel we are interested in.
330 * @param slave_key
331 * The slave requesting the message.
332 * If not NULL, a membership test is performed first
333 * and the message is only returned if the slave has access to it.
334 * @param first_message_id
335 * First message ID to retrieve.
336 * @param last_message_id
337 * Last consecutive message ID to retrieve.
338 * @param fragment_limit
339 * Maximum number of fragments to retrieve.
340 * @param method_prefix
341 * Retrieve only messages with a matching method prefix.
342 * @param fragment_cb
343 * Callback to call with the retrieved fragments.
344 * @param result_cb
345 * Callback to call with the result of the operation.
346 * @param cls
347 * Closure for the callbacks.
348 *
349 * @return Handle that can be used to cancel the operation.
350 */
351struct GNUNET_PSYCSTORE_OperationHandle *
352GNUNET_PSYCSTORE_message_get (struct GNUNET_PSYCSTORE_Handle *h,
353 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
354 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
355 uint64_t first_message_id,
356 uint64_t last_message_id,
357 uint64_t fragment_limit,
358 const char *method_prefix,
359 GNUNET_PSYCSTORE_FragmentCallback fragment_cb,
360 GNUNET_PSYCSTORE_ResultCallback result_cb,
361 void *cls);
362
363
364/**
365 * Retrieve all fragments of the latest messages.
366 *
367 * @param h
368 * Handle for the PSYCstore.
369 * @param channel_key
370 * The channel we are interested in.
371 * @param slave_key
372 * The slave requesting the message.
373 * If not NULL, a membership test is performed first
374 * and the message is only returned if the slave has access to it.
375 * @param message_limit
376 * Maximum number of messages to retrieve.
377 * @param method_prefix
378 * Retrieve only messages with a matching method prefix.
379 * @param fragment_cb
380 * Callback to call with the retrieved fragments.
381 * @param result_cb
382 * Callback to call with the result of the operation.
383 * @param cls
384 * Closure for the callbacks.
385 *
386 * @return Handle that can be used to cancel the operation.
387 */
388struct GNUNET_PSYCSTORE_OperationHandle *
389GNUNET_PSYCSTORE_message_get_latest (struct GNUNET_PSYCSTORE_Handle *h,
390 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
391 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
392 uint64_t message_limit,
393 const char *method_prefix,
394 GNUNET_PSYCSTORE_FragmentCallback fragment_cb,
395 GNUNET_PSYCSTORE_ResultCallback result_cb,
396 void *cls);
397
398
399/**
400 * Retrieve a fragment of message specified by its message ID and fragment
401 * offset.
402 *
403 * @param h
404 * Handle for the PSYCstore.
405 * @param channel_key
406 * The channel we are interested in.
407 * @param slave_key
408 * The slave requesting the message fragment. If not NULL, a membership
409 * test is performed first and the message fragment is only returned
410 * if the slave has access to it.
411 * @param message_id
412 * Message ID to retrieve. Use 0 to get the latest message.
413 * @param fragment_offset
414 * Offset of the fragment to retrieve.
415 * @param fragment_cb
416 * Callback to call with the retrieved fragments.
417 * @param result_cb
418 * Callback to call with the result of the operation.
419 * @param cls
420 * Closure for the callbacks.
421 *
422 * @return Handle that can be used to cancel the operation.
423 */
424struct GNUNET_PSYCSTORE_OperationHandle *
425GNUNET_PSYCSTORE_message_get_fragment (struct GNUNET_PSYCSTORE_Handle *h,
426 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
427 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
428 uint64_t message_id,
429 uint64_t fragment_offset,
430 GNUNET_PSYCSTORE_FragmentCallback fragment_cb,
431 GNUNET_PSYCSTORE_ResultCallback result_cb,
432 void *cls);
433
434
435/**
436 * Callback used to return the latest value of counters for the channel master.
437 *
438 * @see GNUNET_PSYCSTORE_counters_get()
439 *
440 * @param cls Closure.
441 * @param result_code
442 * Status code for the operation:
443 * #GNUNET_OK: success, counter values are returned.
444 * #GNUNET_NO: no message has been sent to the channel yet.
445 * #GNUNET_SYSERR: an error occurred.
446 * @param max_fragment_id
447 * Latest message fragment ID, used by multicast.
448 * @param max_message_id
449 * Latest message ID, used by PSYC.
450 * @param max_group_generation
451 * Latest group generation, used by PSYC.
452 * @param max_state_message_id
453 * Latest message ID containing state modifiers that
454 * was applied to the state store. Used for the state sync process.
455 */
456typedef void
457(*GNUNET_PSYCSTORE_CountersCallback) (void *cls,
458 int result_code,
459 uint64_t max_fragment_id,
460 uint64_t max_message_id,
461 uint64_t max_group_generation,
462 uint64_t max_state_message_id);
463
464
465/**
466 * Retrieve latest values of counters for a channel.
467 *
468 * The current value of counters are needed
469 * - when a channel master is restarted, so that it can continue incrementing
470 * the counters from their last value.
471 * - when a channel slave rejoins and starts the state synchronization process.
472 *
473 * @param h
474 * Handle for the PSYCstore.
475 * @param channel_key
476 * Public key that identifies the channel.
477 * @param counters_cb
478 * Callback to call with the result.
479 * @param cls
480 * Closure for the @a ccb callback.
481 *
482 * @return Handle that can be used to cancel the operation.
483 */
484struct GNUNET_PSYCSTORE_OperationHandle *
485GNUNET_PSYCSTORE_counters_get (struct GNUNET_PSYCSTORE_Handle *h,
486 struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
487 GNUNET_PSYCSTORE_CountersCallback counters_cb,
488 void *cls);
489
490
491/**
492 * Apply modifiers of a message to the current channel state.
493 *
494 * An error is returned if there are missing messages containing state
495 * operations before the current one.
496 *
497 * @param h
498 * Handle for the PSYCstore.
499 * @param channel_key
500 * The channel we are interested in.
501 * @param message_id
502 * ID of the message that contains the @a modifiers.
503 * @param state_delta
504 * Value of the @e state_delta PSYC header variable of the message.
505 * @param result_cb
506 * Callback to call with the result of the operation.
507 * @param cls
508 * Closure for the @a result_cb callback.
509 *
510 * @return Handle that can be used to cancel the operation.
511 */
512struct GNUNET_PSYCSTORE_OperationHandle *
513GNUNET_PSYCSTORE_state_modify (struct GNUNET_PSYCSTORE_Handle *h,
514 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
515 uint64_t message_id,
516 uint64_t state_delta,
517 GNUNET_PSYCSTORE_ResultCallback result_cb,
518 void *cls);
519
520
521/**
522 * Store synchronized state.
523 *
524 * @param h
525 * Handle for the PSYCstore.
526 * @param channel_key
527 * The channel we are interested in.
528 * @param max_state_message_id
529 * ID of the last stateful message before @a state_hash_message_id.
530 * @param state_hash_message_id
531 * ID of the message that contains the state_hash PSYC header variable.
532 * @param modifier_count
533 * Number of elements in the @a modifiers array.
534 * @param modifiers
535 * Full state to store.
536 * @param result_cb
537 * Callback to call with the result of the operation.
538 * @param cls
539 * Closure for the callback.
540 *
541 * @return Handle that can be used to cancel the operation.
542 */
543struct GNUNET_PSYCSTORE_OperationHandle *
544GNUNET_PSYCSTORE_state_sync (struct GNUNET_PSYCSTORE_Handle *h,
545 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
546 uint64_t max_state_message_id,
547 uint64_t state_hash_message_id,
548 size_t modifier_count,
549 const struct GNUNET_PSYC_Modifier *modifiers,
550 GNUNET_PSYCSTORE_ResultCallback result_cb,
551 void *cls);
552
553
554
555/**
556 * Reset the state of a channel.
557 *
558 * Delete all state variables stored for the given channel.
559 *
560 * @param h
561 * Handle for the PSYCstore.
562 * @param channel_key
563 * The channel we are interested in.
564 * @param result_cb
565 * Callback to call with the result of the operation.
566 * @param cls
567 * Closure for the callback.
568 *
569 * @return Handle that can be used to cancel the operation.
570 */
571struct GNUNET_PSYCSTORE_OperationHandle *
572GNUNET_PSYCSTORE_state_reset (struct GNUNET_PSYCSTORE_Handle *h,
573 const struct GNUNET_CRYPTO_EddsaPublicKey
574 *channel_key,
575 GNUNET_PSYCSTORE_ResultCallback result_cb,
576 void *cls);
577
578
579/**
580 * Update signed values of state variables in the state store.
581 *
582 * @param h
583 * Handle for the PSYCstore.
584 * @param channel_key
585 * The channel we are interested in.
586 * @param message_id
587 * Message ID that contained the state @a hash.
588 * @param hash
589 * Hash of the serialized full state.
590 * @param result_cb
591 * Callback to call with the result of the operation.
592 * @param cls
593 * Closure for the callback.
594 *
595 */
596struct GNUNET_PSYCSTORE_OperationHandle *
597GNUNET_PSYCSTORE_state_hash_update (struct GNUNET_PSYCSTORE_Handle *h,
598 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
599 uint64_t message_id,
600 const struct GNUNET_HashCode *hash,
601 GNUNET_PSYCSTORE_ResultCallback result_cb,
602 void *cls);
603
604
605/**
606 * Function called with the value of a state variable.
607 *
608 * @param cls
609 * Closure.
610 * @param name
611 * Name of the state variable. A NULL value indicates that there are no more
612 * state variables to be returned.
613 * @param value
614 * Value of the state variable.
615 * @param value_size
616 * Number of bytes in @a value.
617 *
618 * @return #GNUNET_NO to stop calling this callback with further variables,
619 * #GNUNET_YES to continue.
620 */;
621typedef int
622(*GNUNET_PSYCSTORE_StateCallback) (void *cls, const char *name,
623 const void *value, uint32_t value_size);
624
625
626/**
627 * Retrieve the best matching state variable.
628 *
629 * @param h
630 * Handle for the PSYCstore.
631 * @param channel_key
632 * The channel we are interested in.
633 * @param name
634 * Name of variable to match, the returned variable might be less specific.
635 * @param state_cb
636 * Callback to return the matching state variable.
637 * @param result_cb
638 * Callback to call with the result of the operation.
639 * @param cls
640 * Closure for the callbacks.
641 *
642 * @return Handle that can be used to cancel the operation.
643 */
644struct GNUNET_PSYCSTORE_OperationHandle *
645GNUNET_PSYCSTORE_state_get (struct GNUNET_PSYCSTORE_Handle *h,
646 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
647 const char *name,
648 GNUNET_PSYCSTORE_StateCallback state_cb,
649 GNUNET_PSYCSTORE_ResultCallback result_cb,
650 void *cls);
651
652
653/**
654 * Retrieve all state variables for a channel with the given prefix.
655 *
656 * @param h
657 * Handle for the PSYCstore.
658 * @param channel_key
659 * The channel we are interested in.
660 * @param name_prefix
661 * Prefix of state variable names to match.
662 * @param state_cb
663 * Callback to return matching state variables.
664 * @param result_cb
665 * Callback to call with the result of the operation.
666 * @param cls
667 * Closure for the callbacks.
668 *
669 * @return Handle that can be used to cancel the operation.
670 */
671struct GNUNET_PSYCSTORE_OperationHandle *
672GNUNET_PSYCSTORE_state_get_prefix (struct GNUNET_PSYCSTORE_Handle *h,
673 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
674 const char *name_prefix,
675 GNUNET_PSYCSTORE_StateCallback state_cb,
676 GNUNET_PSYCSTORE_ResultCallback result_cb,
677 void *cls);
678
679
680/**
681 * Cancel an operation.
682 *
683 * @param op Handle for the operation to cancel.
684 */
685int
686GNUNET_PSYCSTORE_operation_cancel (struct GNUNET_PSYCSTORE_OperationHandle *op);
687
688
689
690
691#if 0 /* keep Emacsens' auto-indent happy */
692{
693#endif
694#ifdef __cplusplus
695}
696#endif
697
698/* ifndef GNUNET_PSYCSTORE_SERVICE_H */
699#endif
700
701/** @} */ /* 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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19*/
20
21/**
22 * @author Gabor X Toth
23 * @author Christian Grothoff
24 *
25 * @file
26 * Social service; implements social interactions through the PSYC service.
27 */
28
29/** @defgroup social Social service
30Social interactions through the PSYC service.
31
32# Overview
33
34The social service provides an API for social interactions based on a one-to-many messaging model.
35It manages subscriptions of applications to places, provides messaging functionality in places,
36allows access to the local message history and manages the GNS zone of _egos_ (user identities).
37
38The service stores private and public keys of subscribed places, as well as files received in subscribed places.
39
40# Concepts and terminology
41
42## Ego, Nym
43
44An _ego_ is an identity of a user, a private-public key pair.
45A _nym_ is an identity of another user in the network, identified by its public key.
46Each user can have multiple identities.
47
48struct GNUNET_SOCIAL_Ego and struct GNUNET_SOCIAL_Nym represents one of these identities.
49
50## Place, Host, Guest
51
52A _place_ is where social interactions happen. It is owned and created by an _ego_.
53Creating a new place happens by an _ego_ entering a new place as a _host_,
54where _guests_ can enter later to receive messages sent to the place.
55
56A place is identified by its public key.
57
58- struct GNUNET_SOCIAL_Host represents a place entered as host,
59- struct GNUNET_SOCIAL_Guest is used for a place entered as guest.
60- A struct GNUNET_SOCIAL_Place can be obtained for both a host and guest place
61 using GNUNET_SOCIAL_host_get_place() and GNUNET_SOCIAL_guest_get_place()
62 and can be used with API functions common to hosts and guests.
63
64## History
65
66Messages sent to places are stored locally by the PSYCstore service, and can be queried any time.
67GNUNET_SOCIAL_history_replay_latest() retrieves the latest N messages sent to the place,
68while GNUNET_SOCIAL_history_replay() is used to query a given message ID range.
69
70## GNU Name System
71
72The GNU Name System is used for assigning human-readable names to nyms and places.
73There's a _GNS zone_ corresponding to each _nym_.
74An _ego_ can publish PKEY and PLACE records in its own zone, pointing to nyms and places, respectively.
75
76## Announcement, talk request
77
78The host can _announce_ messages to the place, using GNUNET_SOCIAL_host_announce().
79Guests can send _talk_ requests to the host, using GNUNET_SOCIAL_guest_talk().
80The host receives talk requests of guests and can _relay_ them to the place,
81or process it using a message handler function.
82
83# Using the API
84
85## Connecting to the service
86
87A client first establishes an _application connection_ to the service using
88GNUNET_SOCIAL_app_connect() providing its _application ID_, then receives the
89public keys of subscribed places and available egos in response.
90
91## Reconnecting to places
92
93Then the application can reconnect to its subscribed places by establishing
94_place connections_ with GNUNET_SOCIAL_host_enter_reconnect() and
95GNUNET_SOCIAL_guest_enter_reconnect().
96
97## Subscribing to a place
98
99Entering and subscribing a new host or guest place is done using
100GNUNET_SOCIAL_host_enter() and GNUNET_SOCIAL_guest_enter().
101
102## Disconnecting from a place
103
104An application can disconnect from a place while the social service keeps its
105network connection active, using GNUNET_SOCIAL_host_disconnect() and
106GNUNET_SOCIAL_guest_disconnect().
107
108## Leaving a place
109
110To permanently leave a place, see GNUNET_SOCIAL_host_leave() and GNUNET_SOCIAL_guest_leave().
111When leaving a place its network connections are closed and all applications are unsubscribed from the place.
112
113# Message methods
114
115## _converse
116
117Human conversation in a private or public place.
118
119### Environment
120
121#### _id_reply
122Message ID this message is in reply to.
123
124#### _id_thread
125Thread ID, the first message ID in the thread.
126
127#### _nym_author
128Nym of the author.
129
130FIXME: Are nyms a different data type from egos and person entities?
131Do they have a different format than any other entity address?
132Questions and thoughts on how to fix this in "questions.org"
133
134#### _sig_author
135Signature of the message body and its variables by the author.
136
137### Data
138
139Message body.
140
141## _notice_place
142
143Notification about a place.
144
145TODO: Applications can decide to auto-subscribe to certain places,
146e.g. files under a given size.
147
148### Environment
149
150#### Using GNS
151
152##### _gns_place
153GNS name of the place in a globally unique .zkey zone
154
155FIXME: A custom _gns PSYC data type should be avoidable by parsing
156and interpreting PSYC uniforms appropriately.
157Thoughts on this in "questions.org"
158
159#### Without GNS
160
161##### _key_pub_place
162Public key of place
163
164FIXME: _key_pub can't be the data type for GNUnet-specific cryptographic
165addressing. Questions and thoughts on how to fix this in "questions.org"
166
167##### _peer_origin
168Peer ID of origin
169
170##### _list_peer_relays
171List of peer IDs of relays
172
173## _notice_place_file
174
175Notification about a place hosting a file.
176
177### Environment
178
179The environment of _notice_place above, plus the following:
180
181#### _size_file
182Size of file
183
184#### _type_file
185MIME type of file
186
187#### _name_file
188Name of file
189
190#### _description_file
191Description of file
192
193## _file
194
195Messages with a _file method contain a file,
196which is saved to disk upon reception at the following location:
197$GNUNET_DATA_HOME/social/files/<H(place_pub)>/<H(message_id)>
198
199### Environment
200
201#### _size_file
202Size of file
203
204#### _type_file
205MIME type of file
206
207#### _name_file
208Name of file
209
210#### _description_file
211Description of file
212
213@{
214*/
215
216
217#ifndef GNUNET_SOCIAL_SERVICE_H
218#define GNUNET_SOCIAL_SERVICE_H
219
220#ifdef __cplusplus
221extern "C"
222{
223#if 0 /* keep Emacsens' auto-indent happy */
224}
225#endif
226#endif
227
228#include <stdint.h>
229#include "gnunet_util_lib.h"
230#include "gnunet_psyc_util_lib.h"
231#include "gnunet_identity_service.h"
232#include "gnunet_namestore_service.h"
233#include "gnunet_psyc_service.h"
234
235
236/**
237 * Version number of GNUnet Social API.
238 */
239#define GNUNET_SOCIAL_VERSION 0x00000000
240
241/**
242 * Maximum size of client ID including '\0' terminator.
243 */
244#define GNUNET_SOCIAL_APP_MAX_ID_SIZE 256
245
246enum GNUNET_SOCIAL_MsgProcFlags {
247 GNUNET_SOCIAL_MSG_PROC_NONE = 0,
248 GNUNET_SOCIAL_MSG_PROC_RELAY = 1,
249 GNUNET_SOCIAL_MSG_PROC_SAVE= 2,
250};
251
252/**
253 * Handle for an application.
254 */
255struct GNUNET_SOCIAL_App;
256
257/**
258 * Handle for an ego (own identity)
259 */
260struct GNUNET_SOCIAL_Ego;
261
262/**
263 * Handle for a pseudonym of another user in the network.
264 */
265struct GNUNET_SOCIAL_Nym;
266
267/**
268 * Handle for a place where social interactions happen.
269 */
270struct GNUNET_SOCIAL_Place;
271
272/**
273 * Host handle for a place that we entered.
274 */
275struct GNUNET_SOCIAL_Host;
276
277/**
278 * Guest handle for place that we entered.
279 */
280struct GNUNET_SOCIAL_Guest;
281
282/**
283 * Handle that can be used to reconnect to a place as host.
284 */
285struct GNUNET_SOCIAL_HostConnection;
286
287/**
288 * Handle that can be used to reconnect to a place as guest.
289 */
290struct GNUNET_SOCIAL_GuestConnection;
291
292/**
293 * Notification about an available identity.
294 *
295 * @param cls
296 * Closure.
297 * @param pub_key
298 * Public key of ego.
299 * @param name
300 * Name of ego.
301 */
302typedef void
303(*GNUNET_SOCIAL_AppEgoCallback) (void *cls,
304 struct GNUNET_SOCIAL_Ego *ego,
305 const struct GNUNET_CRYPTO_EcdsaPublicKey *ego_pub_key,
306 const char *name);
307
308
309/**
310 * Entry status of a place per application.
311 */
312enum GNUNET_SOCIAL_AppPlaceState
313{
314 /**
315 * The place was once entered by the ego, but left since.
316 * It's possible to establish a local connection to the place
317 * without re-entering to fetch history from the PSYCstore.
318 * @see enum GNUNET_PSYC_SlaveJoinFlags and GNUNET_SOCIAL_guest_enter()
319 */
320 GNUNET_SOCIAL_PLACE_STATE_ARCHIVED = 0,
321
322 /**
323 * The place is entered by the ego,
324 * but this application is not subscribed to it.
325 */
326 GNUNET_SOCIAL_PLACE_STATE_ENTERED = 1,
327
328 /**
329 * The place is entered by the ego and
330 * and this application is subscribed to it.
331 */
332 GNUNET_SOCIAL_PLACE_STATE_SUBSCRIBED = 2,
333};
334
335
336/**
337 * Called after receiving initial list of egos and places.
338 */
339typedef void
340(*GNUNET_SOCIAL_AppConnectedCallback) (void *cls);
341
342
343/**
344 * Notification about a home.
345 *
346 * @param cls
347 * Closure.
348 * @param hconn
349 * Host connection, to be used with GNUNET_SOCIAL_host_enter_reconnect()
350 * @param ego
351 * Ego used to enter the place.
352 * @param place_pub_key
353 * Public key of the place.
354 * @param place_state
355 * @see enum GNUNET_SOCIAL_AppPlaceState
356 */
357typedef void
358(*GNUNET_SOCIAL_AppHostPlaceCallback) (void *cls,
359 struct GNUNET_SOCIAL_HostConnection *hconn,
360 struct GNUNET_SOCIAL_Ego *ego,
361 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
362 enum GNUNET_SOCIAL_AppPlaceState place_state);
363
364/**
365 * Notification about a place.
366 *
367 * @param cls
368 * Closure.
369 * @param gconn
370 * Guest connection, to be used with GNUNET_SOCIAL_guest_enter_reconnect()
371 * @param ego
372 * Ego used to enter the place.
373 * @param place_pub_key
374 * Public key of the place.
375 * @param place_state
376 * @see enum GNUNET_SOCIAL_AppPlaceState
377 */
378typedef void
379(*GNUNET_SOCIAL_AppGuestPlaceCallback) (void *cls,
380 struct GNUNET_SOCIAL_GuestConnection *gconn,
381 struct GNUNET_SOCIAL_Ego *ego,
382 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
383 enum GNUNET_SOCIAL_AppPlaceState place_state);
384
385
386/**
387 * Establish application connection to the social service.
388 *
389 * The @host_cb and @guest_cb functions are
390 * initially called for each entered places,
391 * then later each time a new place is entered with the current app ID.
392 *
393 * @param cfg
394 * Configuration.
395 * @param ego_cb
396 * Function to notify about an available ego.
397 * @param host_cb
398 * Function to notify about a place entered as host.
399 * @param guest_cb
400 * Function to notify about a place entered as guest.
401 * @param cls
402 * Closure for the callbacks.
403 *
404 * @return Handle that can be used to stop listening.
405 */
406struct GNUNET_SOCIAL_App *
407GNUNET_SOCIAL_app_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
408 const char *id,
409 GNUNET_SOCIAL_AppEgoCallback ego_cb,
410 GNUNET_SOCIAL_AppHostPlaceCallback host_cb,
411 GNUNET_SOCIAL_AppGuestPlaceCallback guest_cb,
412 GNUNET_SOCIAL_AppConnectedCallback connected_cb,
413 void *cls);
414
415
416/**
417 * Disconnect app.
418 *
419 * @param app
420 * Application handle.
421 * @param disconnect_cb
422 * Disconnect callback.
423 * @param disconnect_cls
424 * Disconnect closure.
425 */
426void
427GNUNET_SOCIAL_app_disconnect (struct GNUNET_SOCIAL_App *app,
428 GNUNET_ContinuationCallback disconnect_cb,
429 void *disconnect_cls);
430
431
432/**
433 * Get the public key of @a ego.
434 *
435 * @param ego
436 * Ego.
437 *
438 * @return Public key of ego.
439 */
440const struct GNUNET_CRYPTO_EcdsaPublicKey *
441GNUNET_SOCIAL_ego_get_pub_key (const struct GNUNET_SOCIAL_Ego *ego);
442
443
444/**
445 * Get the name of @a ego.
446 *
447 * @param ego
448 * Ego.
449 *
450 * @return Public key of @a ego.
451 */
452const char *
453GNUNET_SOCIAL_ego_get_name (const struct GNUNET_SOCIAL_Ego *ego);
454
455
456/**
457 * Get the public key of a @a nym.
458 *
459 * Suitable, for example, to be used with GNUNET_SOCIAL_zone_add_nym().
460 *
461 * @param nym
462 * Pseudonym to map to a cryptographic identifier.
463 *
464 * @return Public key of nym.
465 */
466const struct GNUNET_CRYPTO_EcdsaPublicKey *
467GNUNET_SOCIAL_nym_get_pub_key (const struct GNUNET_SOCIAL_Nym *nym);
468
469
470/**
471 * Get the hash of the public key of a @a nym.
472 *
473 * @param nym
474 * Pseudonym to map to a cryptographic identifier.
475 *
476 * @return Hash of the public key of nym.
477 */
478const struct GNUNET_HashCode *
479GNUNET_SOCIAL_nym_get_pub_key_hash (const struct GNUNET_SOCIAL_Nym *nym);
480
481
482/**
483 * Function called asking for nym to be admitted to the place.
484 *
485 * Should call either GNUNET_SOCIAL_host_admit() or
486 * GNUNET_SOCIAL_host_reject_entry() (possibly asynchronously). If this host
487 * cannot decide, it is fine to call neither function, in which case hopefully
488 * some other host of the place exists that will make the decision. The @a nym
489 * reference remains valid until the #GNUNET_SOCIAL_FarewellCallback is invoked
490 * for it.
491 *
492 * @param cls
493 * Closure.
494 * @param nym
495 * Handle for the user who wants to enter.
496 * @param method_name
497 * Method name in the entry request.
498 * @param variable_count
499 * Number of elements in the @a variables array.
500 * @param variables
501 * Variables present in the message.
502 * @param data
503 * Payload given on enter (e.g. a password).
504 * @param data_size
505 * Number of bytes in @a data.
506 */
507typedef void
508(*GNUNET_SOCIAL_AnswerDoorCallback) (void *cls,
509 struct GNUNET_SOCIAL_Nym *nym,
510 const char *method_name,
511 struct GNUNET_PSYC_Environment *env,
512 const void *data,
513 size_t data_size);
514
515
516/**
517 * Function called when a @a nym leaves the place.
518 *
519 * This is also called if the @a nym was never given permission to enter
520 * (i.e. the @a nym stopped asking to get in).
521 *
522 * @param cls
523 * Closure.
524 * @param nym
525 * Handle for the user who left.
526 */
527typedef void
528(*GNUNET_SOCIAL_FarewellCallback) (void *cls,
529 const struct GNUNET_SOCIAL_Nym *nym,
530 struct GNUNET_PSYC_Environment *env);
531
532
533/**
534 * Function called after the host entered a home.
535 *
536 * @param cls
537 * Closure.
538 * @param result
539 * #GNUNET_OK on success, or
540 * #GNUNET_SYSERR on error.
541 * @param place_pub_key
542 * Public key of home.
543 * @param max_message_id
544 * Last message ID sent to the channel.
545 * Or 0 if no messages have been sent to the place yet.
546 */
547typedef void
548(*GNUNET_SOCIAL_HostEnterCallback) (void *cls, int result,
549 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
550 uint64_t max_message_id);
551
552
553/**
554 * Enter a place as host.
555 *
556 * A place is created upon first entering, and it is active until permanently
557 * left using GNUNET_SOCIAL_host_leave().
558 *
559 * @param cfg
560 * Configuration to contact the social service.
561 * @param ego
562 * Identity of the host.
563 * @param place_key
564 * Private-public key pair of the place.
565 * NULL for ephemeral places.
566 * @param policy
567 * Policy specifying entry and history restrictions for the place.
568 * @param slicer
569 * Slicer to handle incoming messages.
570 * @param enter_cb
571 * Function called when the place is entered and ready to use.
572 * @param answer_door_cb
573 * Function to handle new nyms that want to enter.
574 * @param farewell_cb
575 * Function to handle departing nyms.
576 * @param cls
577 * Closure for the callbacks.
578 *
579 * @return Handle for the host.
580 */
581struct GNUNET_SOCIAL_Host *
582GNUNET_SOCIAL_host_enter (const struct GNUNET_SOCIAL_App *app,
583 const struct GNUNET_SOCIAL_Ego *ego,
584 enum GNUNET_PSYC_Policy policy,
585 struct GNUNET_PSYC_Slicer *slicer,
586 GNUNET_SOCIAL_HostEnterCallback enter_cb,
587 GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb,
588 GNUNET_SOCIAL_FarewellCallback farewell_cb,
589 void *cls);
590
591
592/**
593 * Reconnect to an already entered place as host.
594 *
595 * @param hconn
596 * Host connection handle.
597 * @see GNUNET_SOCIAL_app_connect() & GNUNET_SOCIAL_AppHostPlaceCallback()
598 * @param slicer
599 * Slicer to handle incoming messages.
600 * @param enter_cb
601 * Function called when the place is entered and ready to use.
602 * @param answer_door_cb
603 * Function to handle new nyms that want to enter.
604 * @param farewell_cb
605 * Function to handle departing nyms.
606 * @param cls
607 * Closure for the callbacks.
608 *
609 * @return Handle for the host.
610 */
611struct GNUNET_SOCIAL_Host *
612GNUNET_SOCIAL_host_enter_reconnect (struct GNUNET_SOCIAL_HostConnection *hconn,
613 struct GNUNET_PSYC_Slicer *slicer,
614 GNUNET_SOCIAL_HostEnterCallback enter_cb,
615 GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb,
616 GNUNET_SOCIAL_FarewellCallback farewell_cb,
617 void *cls);
618
619
620/**
621 * Decision whether to admit @a nym into the place or refuse entry.
622 *
623 * @param hst
624 * Host of the place.
625 * @param nym
626 * Handle for the entity that wanted to enter.
627 * @param is_admitted
628 * #GNUNET_YES if @a nym is admitted,
629 * #GNUNET_NO if @a nym is refused entry,
630 * #GNUNET_SYSERR if we cannot answer the request.
631 * @param entry_resp
632 * Entry response message, or NULL.
633 * @return #GNUNET_OK on success,
634 * #GNUNET_SYSERR if the message is too large.
635 */
636int
637GNUNET_SOCIAL_host_entry_decision (struct GNUNET_SOCIAL_Host *hst,
638 struct GNUNET_SOCIAL_Nym *nym,
639 int is_admitted,
640 const struct GNUNET_PSYC_Message *entry_resp);
641
642
643/**
644 * Throw @a nym out of the place.
645 *
646 * Sends a _notice_place_leave announcement to the home.
647 *
648 * The @a nym reference will remain valid until the
649 * #GNUNET_SOCIAL_FarewellCallback is invoked,
650 * which should be very soon after this call.
651 *
652 * @param host
653 * Host of the place.
654 * @param nym
655 * Handle for the entity to be ejected.
656 * @param env
657 * Environment for the message or NULL.
658 * _nym is set to @e nym regardless whether an @e env is provided.
659 */
660void
661GNUNET_SOCIAL_host_eject (struct GNUNET_SOCIAL_Host *host,
662 const struct GNUNET_SOCIAL_Nym *nym,
663 struct GNUNET_PSYC_Environment *env);
664
665
666/**
667 * Flags for announcements by a host.
668 */
669enum GNUNET_SOCIAL_AnnounceFlags
670{
671 GNUNET_SOCIAL_ANNOUNCE_NONE = 0,
672
673 /**
674 * Whether this announcement removes all objects from the place.
675 *
676 * New objects can be still added to the now empty place using the @e env
677 * parameter of the same announcement.
678 */
679 GNUNET_SOCIAL_ANNOUNCE_CLEAR_OBJECTS = 1 << 0
680};
681
682
683/**
684 * Handle for an announcement request.
685 */
686struct GNUNET_SOCIAL_Announcement;
687
688
689/**
690 * Send a message to all nyms that are present in the place.
691 *
692 * This function is restricted to the host. Nyms can only send requests
693 * to the host who can decide to relay it to everyone in the place.
694 *
695 * @param host
696 * Host of the place.
697 * @param method_name
698 * Method to use for the announcement.
699 * @param env
700 * Environment containing variables for the message and operations
701 * on objects of the place.
702 * Has to remain available until the first call to @a notify_data.
703 * Can be NULL.
704 * @param notify_data
705 * Function to call to get the payload of the announcement.
706 * @param notify_data_cls
707 * Closure for @a notify.
708 * @param flags
709 * Flags for this announcement.
710 *
711 * @return NULL on error (another announcement already in progress?).
712 */
713struct GNUNET_SOCIAL_Announcement *
714GNUNET_SOCIAL_host_announce (struct GNUNET_SOCIAL_Host *host,
715 const char *method_name,
716 const struct GNUNET_PSYC_Environment *env,
717 GNUNET_PSYC_TransmitNotifyData notify_data,
718 void *notify_data_cls,
719 enum GNUNET_SOCIAL_AnnounceFlags flags);
720
721
722/**
723 * Resume transmitting announcement.
724 *
725 * @param a
726 * The announcement to resume.
727 */
728void
729GNUNET_SOCIAL_host_announce_resume (struct GNUNET_SOCIAL_Announcement *a);
730
731
732/**
733 * Cancel announcement.
734 *
735 * @param a
736 * The announcement to cancel.
737 */
738void
739GNUNET_SOCIAL_host_announce_cancel (struct GNUNET_SOCIAL_Announcement *a);
740
741
742/**
743 * Allow relaying messages from guests matching a given @a method_prefix.
744 *
745 * @param host
746 * The host.
747 * @param method_prefix
748 * Method prefix to allow.
749 */
750void
751GNUNET_SOCIAL_host_relay_allow_method (struct GNUNET_SOCIAL_Host *host,
752 const char *method_prefix);
753
754
755/**
756 * Allow relaying changes to objects of the place.
757 *
758 * Only applies to messages with an allowed method name.
759 * @see GNUNET_SCOIAL_host_relay_allow_method()
760 *
761 * @param host
762 * The host.
763 * @param object_prefix
764 * Object prefix to allow modifying.
765 */
766void
767GNUNET_SOCIAL_host_relay_allow_method (struct GNUNET_SOCIAL_Host *host,
768 const char *object_prefix);
769
770
771/**
772 * Stop relaying messages from guests.
773 *
774 * Remove all allowed relay rules.
775 *
776 *
777 *
778 */
779void
780GNUNET_SOCIAL_host_relay_stop (struct GNUNET_SOCIAL_Host *host);
781
782
783/**
784 * Obtain handle for a hosted place.
785 *
786 * The returned handle can be used to access the place API.
787 *
788 * @param host
789 * Handle for the host.
790 *
791 * @return Handle for the hosted place, valid as long as @a host is valid.
792 */
793struct GNUNET_SOCIAL_Place *
794GNUNET_SOCIAL_host_get_place (struct GNUNET_SOCIAL_Host *host);
795
796
797/**
798 * Disconnect from a home.
799 *
800 * Invalidates host handle.
801 *
802 * @param hst
803 * The host to disconnect.
804 * @param disconnect_cb
805 * Function called after disconnected from the service.
806 * @param cls
807 * Closure for @a disconnect_cb.
808 */
809void
810GNUNET_SOCIAL_host_disconnect (struct GNUNET_SOCIAL_Host *hst,
811 GNUNET_ContinuationCallback disconnect_cb,
812 void *cls);
813
814
815/**
816 * Stop hosting a home.
817 *
818 * Sends a _notice_place_closing announcement to the home.
819 * Invalidates host handle.
820 *
821 * @param hst
822 * Host leaving.
823 * @param env
824 * Environment for the message or NULL.
825 * @param disconnect_cb
826 * Function called after the host left the place
827 * and disconnected from the service.
828 * @param cls
829 * Closure for @a disconnect_cb.
830 */
831void
832GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *hst,
833 const struct GNUNET_PSYC_Environment *env,
834 GNUNET_ContinuationCallback disconnect_cb,
835 void *cls);
836
837
838/**
839 * Function called after the guest entered the local copy of the place.
840 *
841 * History and object query functions can be used after this call,
842 * but new messages can't be sent or received.
843 *
844 * @param cls
845 * Closure.
846 * @param result
847 * #GNUNET_OK on success, or
848 * #GNUNET_SYSERR on error, e.g. could not connect to the service, or
849 * could not resolve GNS name.
850 * @param place_pub_key
851 * Public key of place.
852 * @param max_message_id
853 * Last message ID sent to the place.
854 * Or 0 if no messages have been sent to the place yet.
855 */
856typedef void
857(*GNUNET_SOCIAL_GuestEnterCallback) (void *cls, int result,
858 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
859 uint64_t max_message_id);
860
861
862/**
863 * Function called upon a guest receives a decision about entry to the place.
864 *
865 * @param is_admitted
866 * Is the guest admitted to the place?
867 * #GNUNET_YES if admitted,
868 * #GNUNET_NO if refused entry,
869 * #GNUNET_SYSERR if the request could not be answered.
870 * @param data
871 * Entry response message.
872 */
873typedef void
874(*GNUNET_SOCIAL_EntryDecisionCallback) (void *cls,
875 int is_admitted,
876 const struct GNUNET_PSYC_Message *entry_resp);
877
878
879/**
880 * Request entry to a place as a guest.
881 *
882 * @param app
883 * Application handle.
884 * @param ego
885 * Identity of the guest.
886 * @param place_pub_key
887 * Public key of the place to enter.
888 * @param flags
889 * Flags for the entry.
890 * @param origin
891 * Peer identity of the origin of the underlying multicast group.
892 * @param relay_count
893 * Number of elements in the @a relays array.
894 * @param relays
895 * Relays for the underlying multicast group.
896 * @param entry_msg
897 * Entry message.
898 * @param slicer
899 * Slicer to use for processing incoming requests from guests.
900 *
901 * @return NULL on errors, otherwise handle for the guest.
902 */
903struct GNUNET_SOCIAL_Guest *
904GNUNET_SOCIAL_guest_enter (const struct GNUNET_SOCIAL_App *app,
905 const struct GNUNET_SOCIAL_Ego *ego,
906 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
907 enum GNUNET_PSYC_SlaveJoinFlags flags,
908 const struct GNUNET_PeerIdentity *origin,
909 uint32_t relay_count,
910 const struct GNUNET_PeerIdentity *relays,
911 const struct GNUNET_PSYC_Message *entry_msg,
912 struct GNUNET_PSYC_Slicer *slicer,
913 GNUNET_SOCIAL_GuestEnterCallback local_enter_cb,
914 GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb,
915 void *cls);
916
917
918/**
919 * Request entry to a place by name as a guest.
920 *
921 * @param app
922 * Application handle.
923 * @param ego
924 * Identity of the guest.
925 * @param gns_name
926 * GNS name of the place to enter. Either in the form of
927 * 'room.friend.gnu', or 'NYMPUBKEY.zkey'. This latter case refers to
928 * the 'PLACE' record of the empty label ("+") in the GNS zone with the
929 * nym's public key 'NYMPUBKEY', and can be used to request entry to a
930 * pseudonym's place directly.
931 * @param password
932 * Password to decrypt the record, or NULL for cleartext records.
933 * @param join_msg
934 * Entry request message.
935 * @param slicer
936 * Slicer to use for processing incoming requests from guests.
937 * @param local_enter_cb
938 * Called upon connection established to the social service.
939 * @param entry_decision_cb
940 * Called upon receiving entry decision.
941 *
942 * @return NULL on errors, otherwise handle for the guest.
943 */
944struct GNUNET_SOCIAL_Guest *
945GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_SOCIAL_App *app,
946 const struct GNUNET_SOCIAL_Ego *ego,
947 const char *gns_name,
948 const char *password,
949 const struct GNUNET_PSYC_Message *join_msg,
950 struct GNUNET_PSYC_Slicer *slicer,
951 GNUNET_SOCIAL_GuestEnterCallback local_enter_cb,
952 GNUNET_SOCIAL_EntryDecisionCallback entry_decision_cb,
953 void *cls);
954
955
956/**
957 * Reconnect to an already entered place as guest.
958 *
959 * @param gconn
960 * Guest connection handle.
961 * @see GNUNET_SOCIAL_app_connect() & GNUNET_SOCIAL_AppGuestPlaceCallback()
962 * @param flags
963 * Flags for the entry.
964 * @param slicer
965 * Slicer to use for processing incoming requests from guests.
966 * @param local_enter_cb
967 * Called upon connection established to the social service.
968 * @param entry_decision_cb
969 * Called upon receiving entry decision.
970 *
971 * @return NULL on errors, otherwise handle for the guest.
972 */
973struct GNUNET_SOCIAL_Guest *
974GNUNET_SOCIAL_guest_enter_reconnect (struct GNUNET_SOCIAL_GuestConnection *gconn,
975 enum GNUNET_PSYC_SlaveJoinFlags flags,
976 struct GNUNET_PSYC_Slicer *slicer,
977 GNUNET_SOCIAL_GuestEnterCallback local_enter_cb,
978 void *cls);
979
980
981/**
982 * Flags for talking to the host of a place.
983 */
984enum GNUNET_SOCIAL_TalkFlags
985{
986 GNUNET_SOCIAL_TALK_NONE = 0
987};
988
989
990/**
991 * A talk request.
992 */
993struct GNUNET_SOCIAL_TalkRequest;
994
995
996/**
997 * Talk to the host of the place.
998 *
999 * @param place
1000 * Place where we want to talk to the host.
1001 * @param method_name
1002 * Method to invoke on the host.
1003 * @param env
1004 * Environment containing variables for the message, or NULL.
1005 * @param notify_data
1006 * Function to use to get the payload for the method.
1007 * @param notify_data_cls
1008 * Closure for @a notify_data.
1009 * @param flags
1010 * Flags for the message being sent.
1011 *
1012 * @return NULL if we are already trying to talk to the host,
1013 * otherwise handle to cancel the request.
1014 */
1015struct GNUNET_SOCIAL_TalkRequest *
1016GNUNET_SOCIAL_guest_talk (struct GNUNET_SOCIAL_Guest *guest,
1017 const char *method_name,
1018 const struct GNUNET_PSYC_Environment *env,
1019 GNUNET_PSYC_TransmitNotifyData notify_data,
1020 void *notify_data_cls,
1021 enum GNUNET_SOCIAL_TalkFlags flags);
1022
1023
1024/**
1025 * Resume talking to the host of the place.
1026 *
1027 * @param tr
1028 * Talk request to resume.
1029 */
1030void
1031GNUNET_SOCIAL_guest_talk_resume (struct GNUNET_SOCIAL_TalkRequest *tr);
1032
1033
1034/**
1035 * Cancel talking to the host of the place.
1036 *
1037 * @param tr
1038 * Talk request to cancel.
1039 */
1040void
1041GNUNET_SOCIAL_guest_talk_cancel (struct GNUNET_SOCIAL_TalkRequest *tr);
1042
1043
1044/**
1045 * Disconnect from a place.
1046 *
1047 * Invalidates guest handle.
1048 *
1049 * @param gst
1050 * The guest to disconnect.
1051 * @param disconnect_cb
1052 * Function called after disconnected from the service.
1053 * @param cls
1054 * Closure for @a disconnect_cb.
1055 */
1056void
1057GNUNET_SOCIAL_guest_disconnect (struct GNUNET_SOCIAL_Guest *gst,
1058 GNUNET_ContinuationCallback disconnect_cb,
1059 void *cls);
1060
1061
1062/**
1063 * Leave a place temporarily or permanently.
1064 *
1065 * Notifies the owner of the place about leaving, and destroys the place handle.
1066 *
1067 * @param place
1068 * Place to leave.
1069 * @param env
1070 * Optional environment for the leave message if @a keep_active
1071 * is #GNUNET_NO. NULL if not needed.
1072 * @param disconnect_cb
1073 * Called upon disconnecting from the social service.
1074 */
1075void
1076GNUNET_SOCIAL_guest_leave (struct GNUNET_SOCIAL_Guest *gst,
1077 struct GNUNET_PSYC_Environment *env,
1078 GNUNET_ContinuationCallback disconnect_cb,
1079 void *leave_cls);
1080
1081
1082/**
1083 * Obtain handle for a place entered as guest.
1084 *
1085 * The returned handle can be used to access the place API.
1086 *
1087 * @param guest Handle for the guest.
1088 *
1089 * @return Handle for the place, valid as long as @a guest is valid.
1090 */
1091struct GNUNET_SOCIAL_Place *
1092GNUNET_SOCIAL_guest_get_place (struct GNUNET_SOCIAL_Guest *guest);
1093
1094
1095/**
1096 * A history request.
1097 */
1098struct GNUNET_SOCIAL_HistoryRequest;
1099
1100
1101/**
1102 * Get the public key of a place.
1103 *
1104 * @param plc
1105 * Place.
1106 *
1107 * @return Public key of the place.
1108 */
1109const struct GNUNET_CRYPTO_EddsaPublicKey *
1110GNUNET_SOCIAL_place_get_pub_key (const struct GNUNET_SOCIAL_Place *plc);
1111
1112
1113/**
1114 * Set message processing @a flags for a @a method_prefix.
1115 *
1116 * @param plc
1117 * Place.
1118 * @param method_prefix
1119 * Method prefix @a flags apply to.
1120 * @param flags
1121 * The flags that apply to a matching @a method_prefix.
1122 */
1123void
1124GNUNET_SOCIAL_place_msg_proc_set (struct GNUNET_SOCIAL_Place *plc,
1125 const char *method_prefix,
1126 enum GNUNET_SOCIAL_MsgProcFlags flags);
1127
1128/**
1129 * Clear all message processing flags previously set for this place.
1130 */
1131void
1132GNUNET_SOCIAL_place_msg_proc_clear (struct GNUNET_SOCIAL_Place *plc);
1133
1134
1135/**
1136 * Learn about the history of a place.
1137 *
1138 * Messages are returned through the @a slicer function
1139 * and have the #GNUNET_PSYC_MESSAGE_HISTORIC flag set.
1140 *
1141 * @param place
1142 * Place we want to learn more about.
1143 * @param start_message_id
1144 * First historic message we are interested in.
1145 * @param end_message_id
1146 * Last historic message we are interested in (inclusive).
1147 * @param method_prefix
1148 * Only retrieve messages with this method prefix.
1149 * @param flags
1150 * OR'ed GNUNET_PSYC_HistoryReplayFlags
1151 * @param slicer
1152 * Slicer to use for retrieved messages.
1153 * Can be the same as the slicer of the place.
1154 * @param result_cb
1155 * Function called after all messages retrieved.
1156 * NULL if not needed.
1157 * @param cls Closure for @a result_cb.
1158 */
1159struct GNUNET_SOCIAL_HistoryRequest *
1160GNUNET_SOCIAL_place_history_replay (struct GNUNET_SOCIAL_Place *plc,
1161 uint64_t start_message_id,
1162 uint64_t end_message_id,
1163 const char *method_prefix,
1164 uint32_t flags,
1165 struct GNUNET_PSYC_Slicer *slicer,
1166 GNUNET_ResultCallback result_cb,
1167 void *cls);
1168
1169
1170/**
1171 * Learn about the history of a place.
1172 *
1173 * Sends messages through the slicer function of the place where
1174 * start_message_id <= message_id <= end_message_id.
1175 * The messages will have the #GNUNET_PSYC_MESSAGE_HISTORIC flag set.
1176 *
1177 * To get the latest message, use 0 for both the start and end message ID.
1178 *
1179 * @param place
1180 * Place we want to learn more about.
1181 * @param message_limit
1182 * Maximum number of historic messages we are interested in.
1183 * @param result_cb
1184 * Function called after all messages retrieved.
1185 * NULL if not needed.
1186 * @param cls Closure for @a result_cb.
1187 */
1188struct GNUNET_SOCIAL_HistoryRequest *
1189GNUNET_SOCIAL_place_history_replay_latest (struct GNUNET_SOCIAL_Place *plc,
1190 uint64_t message_limit,
1191 const char *method_prefix,
1192 uint32_t flags,
1193 struct GNUNET_PSYC_Slicer *slicer,
1194 GNUNET_ResultCallback result_cb,
1195 void *cls);
1196
1197/**
1198 * Cancel learning about the history of a place.
1199 *
1200 * @param hist
1201 * History lesson to cancel.
1202 */
1203void
1204GNUNET_SOCIAL_place_history_replay_cancel (struct GNUNET_SOCIAL_HistoryRequest *hist);
1205
1206
1207struct GNUNET_SOCIAL_LookHandle;
1208
1209
1210/**
1211 * Look at a particular object in the place.
1212 *
1213 * The best matching object is returned (its name might be less specific than
1214 * what was requested).
1215 *
1216 * @param place
1217 * The place to look the object at.
1218 * @param full_name
1219 * Full name of the object.
1220 *
1221 * @return NULL if there is no such object at this place.
1222 */
1223struct GNUNET_SOCIAL_LookHandle *
1224GNUNET_SOCIAL_place_look_at (struct GNUNET_SOCIAL_Place *plc,
1225 const char *full_name,
1226 GNUNET_PSYC_StateVarCallback var_cb,
1227 GNUNET_ResultCallback result_cb,
1228 void *cls);
1229
1230/**
1231 * Look for objects in the place with a matching name prefix.
1232 *
1233 * @param place
1234 * The place to look its objects at.
1235 * @param name_prefix
1236 * Look at objects with names beginning with this value.
1237 * @param var_cb
1238 * Function to call for each object found.
1239 * @param cls
1240 * Closure for callback function.
1241 *
1242 * @return Handle that can be used to stop looking at objects.
1243 */
1244struct GNUNET_SOCIAL_LookHandle *
1245GNUNET_SOCIAL_place_look_for (struct GNUNET_SOCIAL_Place *plc,
1246 const char *name_prefix,
1247 GNUNET_PSYC_StateVarCallback var_cb,
1248 GNUNET_ResultCallback result_cb,
1249 void *cls);
1250
1251
1252/**
1253 * Stop looking at objects.
1254 *
1255 * @param lh Look handle to stop.
1256 */
1257void
1258GNUNET_SOCIAL_place_look_cancel (struct GNUNET_SOCIAL_LookHandle *lh);
1259
1260
1261/**
1262 * Advertise a @e place in the GNS zone of @a ego.
1263 *
1264 * @param app
1265 * Application handle.
1266 * @param ego
1267 * Ego.
1268 * @param place_pub_key
1269 * Public key of place to add.
1270 * @param name
1271 * The name for the PLACE record to put in the zone.
1272 * @param password
1273 * Password used to encrypt the record or NULL to keep it cleartext.
1274 * @param relay_count
1275 * Number of elements in the @a relays array.
1276 * @param relays
1277 * List of relays to put in the PLACE record to advertise
1278 * as entry points to the place in addition to the origin.
1279 * @param expiration_time
1280 * Expiration time of the record, use 0 to remove the record.
1281 * @param result_cb
1282 * Function called with the result of the operation.
1283 * @param result_cls
1284 * Closure for @a result_cb
1285 *
1286 * @return #GNUNET_OK if the request was sent,
1287 * #GNUNET_SYSERR on error, e.g. the name/password is too long.
1288 */
1289int
1290GNUNET_SOCIAL_zone_add_place (const struct GNUNET_SOCIAL_App *app,
1291 const struct GNUNET_SOCIAL_Ego *ego,
1292 const char *name,
1293 const char *password,
1294 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
1295 const struct GNUNET_PeerIdentity *origin,
1296 uint32_t relay_count,
1297 const struct GNUNET_PeerIdentity *relays,
1298 struct GNUNET_TIME_Absolute expiration_time,
1299 GNUNET_ResultCallback result_cb,
1300 void *result_cls);
1301
1302
1303/**
1304 * Add public key to the GNS zone of the @e ego.
1305 *
1306 * @param cfg
1307 * Configuration.
1308 * @param ego
1309 * Ego.
1310 * @param name
1311 * The name for the PKEY record to put in the zone.
1312 * @param nym_pub_key
1313 * Public key of nym to add.
1314 * @param expiration_time
1315 * Expiration time of the record, use 0 to remove the record.
1316 * @param result_cb
1317 * Function called with the result of the operation.
1318 * @param result_cls
1319 * Closure for @a result_cb
1320 *
1321 * @return #GNUNET_OK if the request was sent,
1322 * #GNUNET_SYSERR on error, e.g. the name is too long.
1323 */
1324int
1325GNUNET_SOCIAL_zone_add_nym (const struct GNUNET_SOCIAL_App *app,
1326 const struct GNUNET_SOCIAL_Ego *ego,
1327 const char *name,
1328 const struct GNUNET_CRYPTO_EcdsaPublicKey *nym_pub_key,
1329 struct GNUNET_TIME_Absolute expiration_time,
1330 GNUNET_ResultCallback result_cb,
1331 void *result_cls);
1332
1333
1334#if 0 /* keep Emacsens' auto-indent happy */
1335{
1336#endif
1337#ifdef __cplusplus
1338}
1339#endif
1340
1341/* ifndef GNUNET_SOCIAL_SERVICE_H */
1342#endif
1343
1344/** @} */ /* 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 @@
1gnunet-service-multicast
2gnunet-multicast
3test_multicast
4test_multicast_multipeer
5test_multicast_2peers
6test_multicast_multipeer_line
7test_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 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4pkgcfgdir= $(pkgdatadir)/config.d/
5
6libexecdir= $(pkglibdir)/libexec/
7
8pkgcfg_DATA = \
9 multicast.conf
10
11if MINGW
12 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
13endif
14
15if USE_COVERAGE
16 AM_CFLAGS = -fprofile-arcs -ftest-coverage
17endif
18
19lib_LTLIBRARIES = libgnunetmulticast.la
20
21libgnunetmulticast_la_SOURCES = \
22 multicast_api.c multicast.h
23libgnunetmulticast_la_LIBADD = \
24 $(top_builddir)/src/util/libgnunetutil.la \
25 $(GN_LIBINTL) $(XLIB)
26libgnunetmulticast_la_LDFLAGS = \
27 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
28 -version-info 0:0:0
29
30
31bin_PROGRAMS = \
32 gnunet-multicast
33
34libexec_PROGRAMS = \
35 gnunet-service-multicast \
36 $(EXP_LIBEXEC)
37
38gnunet_multicast_SOURCES = \
39 gnunet-multicast.c
40gnunet_multicast_LDADD = \
41 $(top_builddir)/src/util/libgnunetutil.la \
42 $(GN_LIBINTL)
43
44gnunet_service_multicast_SOURCES = \
45 gnunet-service-multicast.c
46gnunet_service_multicast_LDADD = \
47 $(top_builddir)/src/util/libgnunetutil.la \
48 $(top_builddir)/src/cadet/libgnunetcadet.la \
49 $(top_builddir)/src/statistics/libgnunetstatistics.la \
50 $(GN_LIBINTL)
51
52check_PROGRAMS = \
53 test_multicast \
54 test_multicast_multipeer_star \
55 test_multicast_multipeer_line
56
57if ENABLE_TEST_RUN
58AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@}; export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; unset XDG_DATA_HOME; unset XDG_CONFIG_HOME;
59TESTS = $(check_PROGRAMS)
60endif
61
62test_multicast_SOURCES = \
63 test_multicast.c
64test_multicast_LDADD = \
65 libgnunetmulticast.la \
66 $(top_builddir)/src/testing/libgnunettesting.la \
67 $(top_builddir)/src/util/libgnunetutil.la
68test_multicast_multipeer_star_SOURCES = \
69 test_multicast_multipeer.c
70test_multicast_multipeer_star_LDADD = \
71 libgnunetmulticast.la \
72 $(top_builddir)/src/testbed/libgnunettestbed.la \
73 $(top_builddir)/src/util/libgnunetutil.la
74test_multicast_multipeer_line_SOURCES = \
75 test_multicast_multipeer.c
76test_multicast_multipeer_line_LDADD = \
77 libgnunetmulticast.la \
78 $(top_builddir)/src/testbed/libgnunettestbed.la \
79 $(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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19*/
20
21/**
22 * @file multicast/gnunet-multicast.c
23 * @brief multicast for writing a tool
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28/* #include "gnunet_multicast_service.h" */
29
30/**
31 * Final status code.
32 */
33static int ret;
34
35/**
36 * Main function that will be run by the scheduler.
37 *
38 * @param cls closure
39 * @param args remaining command-line arguments
40 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
41 * @param cfg configuration
42 */
43static void
44run (void *cls, char *const *args, const char *cfgfile,
45 const struct GNUNET_CONFIGURATION_Handle *cfg)
46{
47 /* main code here */
48 puts( gettext_noop ("This command doesn't do anything yet.") );
49 ret = -1;
50}
51
52
53/**
54 * The main function.
55 *
56 * @param argc number of arguments from the command line
57 * @param argv command line arguments
58 * @return 0 ok, 1 on error
59 */
60int
61main (int argc, char *const *argv)
62{
63 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
64 /* FIMXE: add options here */
65 GNUNET_GETOPT_OPTION_END
66 };
67 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
68 return 2;
69
70 ret = (GNUNET_OK ==
71 GNUNET_PROGRAM_run (argc, argv, "gnunet-multicast",
72 gettext_noop ("This command doesn't do anything yet."),
73 options, &run,
74 NULL)) ? ret : 1;
75 GNUNET_free ((void*) argv);
76 return ret;
77}
78
79/* 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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19*/
20
21/**
22 * @file multicast/gnunet-service-multicast.c
23 * @brief program that does multicast
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_signatures.h"
29#include "gnunet_applications.h"
30#include "gnunet_statistics_service.h"
31#include "gnunet_cadet_service.h"
32#include "gnunet_multicast_service.h"
33#include "multicast.h"
34
35/**
36 * Handle to our current configuration.
37 */
38static const struct GNUNET_CONFIGURATION_Handle *cfg;
39
40/**
41 * Service handle.
42 */
43static struct GNUNET_SERVICE_Handle *service;
44
45/**
46 * CADET handle.
47 */
48static struct GNUNET_CADET_Handle *cadet;
49
50/**
51 * Identity of this peer.
52 */
53static struct GNUNET_PeerIdentity this_peer;
54
55/**
56 * Handle to the statistics service.
57 */
58static struct GNUNET_STATISTICS_Handle *stats;
59
60/**
61 * All connected origin clients.
62 * Group's pub_key_hash -> struct Origin * (uniq)
63 */
64static struct GNUNET_CONTAINER_MultiHashMap *origins;
65
66/**
67 * All connected member clients.
68 * Group's pub_key_hash -> struct Member * (multi)
69 */
70static struct GNUNET_CONTAINER_MultiHashMap *members;
71
72/**
73 * Connected member clients per group.
74 * Group's pub_key_hash -> Member's pub_key_hash (uniq) -> struct Member * (uniq)
75 */
76static struct GNUNET_CONTAINER_MultiHashMap *group_members;
77
78/**
79 * Incoming CADET channels with connected children in the tree.
80 * Group's pub_key_hash -> struct Channel * (multi)
81 */
82static struct GNUNET_CONTAINER_MultiHashMap *channels_in;
83
84/**
85 * Outgoing CADET channels connecting to parents in the tree.
86 * Group's pub_key_hash -> struct Channel * (multi)
87 */
88static struct GNUNET_CONTAINER_MultiHashMap *channels_out;
89
90/**
91 * Incoming replay requests from CADET.
92 * Group's pub_key_hash ->
93 * H(fragment_id, message_id, fragment_offset, flags) -> struct Channel *
94 */
95static struct GNUNET_CONTAINER_MultiHashMap *replay_req_cadet;
96
97/**
98 * Incoming replay requests from clients.
99 * Group's pub_key_hash ->
100 * H(fragment_id, message_id, fragment_offset, flags) -> struct GNUNET_SERVICE_Client *
101 */
102static struct GNUNET_CONTAINER_MultiHashMap *replay_req_client;
103
104
105/**
106 * Join status of a remote peer.
107 */
108enum JoinStatus
109{
110 JOIN_REFUSED = -1,
111 JOIN_NOT_ASKED = 0,
112 JOIN_WAITING = 1,
113 JOIN_ADMITTED = 2,
114};
115
116enum ChannelDirection
117{
118 DIR_INCOMING = 0,
119 DIR_OUTGOING = 1,
120};
121
122
123/**
124 * Context for a CADET channel.
125 */
126struct Channel
127{
128 /**
129 * Group the channel belongs to.
130 *
131 * Only set for outgoing channels.
132 */
133 struct Group *group;
134
135 /**
136 * CADET channel.
137 */
138 struct GNUNET_CADET_Channel *channel;
139
140 // FIXME: not used
141 /**
142 * CADET transmission handle.
143 */
144 struct GNUNET_CADET_TransmitHandle *tmit_handle;
145
146 /**
147 * Public key of the target group.
148 */
149 struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key;
150
151 /**
152 * Hash of @a group_pub_key.
153 */
154 struct GNUNET_HashCode group_pub_hash;
155
156 /**
157 * Public key of the joining member.
158 */
159 struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
160
161 /**
162 * Remote peer identity.
163 */
164 struct GNUNET_PeerIdentity peer;
165
166 /**
167 * Current window size, set by cadet_notify_window_change()
168 */
169 int32_t window_size;
170
171 /**
172 * Is the connection established?
173 */
174 int8_t is_connected;
175
176 /**
177 * Is the remote peer admitted to the group?
178 * @see enum JoinStatus
179 */
180 int8_t join_status;
181
182 /**
183 * Number of messages waiting to be sent to CADET.
184 */
185 uint8_t msgs_pending;
186
187 /**
188 * Channel direction.
189 * @see enum ChannelDirection
190 */
191 uint8_t direction;
192};
193
194
195/**
196 * List of connected clients.
197 */
198struct ClientList
199{
200 struct ClientList *prev;
201 struct ClientList *next;
202 struct GNUNET_SERVICE_Client *client;
203};
204
205
206/**
207 * Client context for an origin or member.
208 */
209struct Group
210{
211 struct ClientList *clients_head;
212 struct ClientList *clients_tail;
213
214 /**
215 * Public key of the group.
216 */
217 struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
218
219 /**
220 * Hash of @a pub_key.
221 */
222 struct GNUNET_HashCode pub_key_hash;
223
224 /**
225 * CADET port hash.
226 */
227 struct GNUNET_HashCode cadet_port_hash;
228
229 /**
230 * Is the client disconnected? #GNUNET_YES or #GNUNET_NO
231 */
232 uint8_t is_disconnected;
233
234 /**
235 * Is this an origin (#GNUNET_YES), or member (#GNUNET_NO)?
236 */
237 uint8_t is_origin;
238
239 union {
240 struct Origin *origin;
241 struct Member *member;
242 };
243};
244
245
246/**
247* Client context for a group's origin.
248 */
249struct Origin
250{
251 struct Group group;
252
253 /**
254 * Private key of the group.
255 */
256 struct GNUNET_CRYPTO_EddsaPrivateKey priv_key;
257
258 /**
259 * CADET port.
260 */
261 struct GNUNET_CADET_Port *cadet_port;
262
263 /**
264 * Last message fragment ID sent to the group.
265 */
266 uint64_t max_fragment_id;
267};
268
269
270/**
271 * Client context for a group member.
272 */
273struct Member
274{
275 struct Group group;
276
277 /**
278 * Private key of the member.
279 */
280 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
281
282 /**
283 * Public key of the member.
284 */
285 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
286
287 /**
288 * Hash of @a pub_key.
289 */
290 struct GNUNET_HashCode pub_key_hash;
291
292 /**
293 * Join request sent to the origin / members.
294 */
295 struct MulticastJoinRequestMessage *join_req;
296
297 /**
298 * Join decision sent in reply to our request.
299 *
300 * Only a positive decision is stored here, in case of a negative decision the
301 * client is disconnected.
302 */
303 struct MulticastJoinDecisionMessageHeader *join_dcsn;
304
305 /**
306 * CADET channel to the origin.
307 */
308 struct Channel *origin_channel;
309
310 /**
311 * Peer identity of origin.
312 */
313 struct GNUNET_PeerIdentity origin;
314
315 /**
316 * Peer identity of relays (other members to connect).
317 */
318 struct GNUNET_PeerIdentity *relays;
319
320 /**
321 * Last request fragment ID sent to the origin.
322 */
323 uint64_t max_fragment_id;
324
325 /**
326 * Number of @a relays.
327 */
328 uint32_t relay_count;
329};
330
331
332/**
333 * Client context.
334 */
335struct Client {
336 struct GNUNET_SERVICE_Client *client;
337 struct Group *group;
338};
339
340
341struct ReplayRequestKey
342{
343 uint64_t fragment_id;
344 uint64_t message_id;
345 uint64_t fragment_offset;
346 uint64_t flags;
347};
348
349
350static struct Channel *
351cadet_channel_create (struct Group *grp, struct GNUNET_PeerIdentity *peer);
352
353static void
354cadet_channel_destroy (struct Channel *chn);
355
356static void
357client_send_join_decision (struct Member *mem,
358 const struct MulticastJoinDecisionMessageHeader *hdcsn);
359
360
361/**
362 * Task run during shutdown.
363 *
364 * @param cls unused
365 */
366static void
367shutdown_task (void *cls)
368{
369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
370 "shutting down\n");
371 if (NULL != cadet)
372 {
373 GNUNET_CADET_disconnect (cadet);
374 cadet = NULL;
375 }
376 if (NULL != stats)
377 {
378 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
379 stats = NULL;
380 }
381 /* FIXME: do more clean up here */
382}
383
384
385/**
386 * Clean up origin data structures after a client disconnected.
387 */
388static void
389cleanup_origin (struct Origin *orig)
390{
391 struct Group *grp = &orig->group;
392 GNUNET_CONTAINER_multihashmap_remove (origins, &grp->pub_key_hash, orig);
393 if (NULL != orig->cadet_port)
394 {
395 GNUNET_CADET_close_port (orig->cadet_port);
396 orig->cadet_port = NULL;
397 }
398 GNUNET_free (orig);
399}
400
401
402/**
403 * Clean up member data structures after a client disconnected.
404 */
405static void
406cleanup_member (struct Member *mem)
407{
408 struct Group *grp = &mem->group;
409 struct GNUNET_CONTAINER_MultiHashMap *
410 grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members,
411 &grp->pub_key_hash);
412 GNUNET_assert (NULL != grp_mem);
413 GNUNET_CONTAINER_multihashmap_remove (grp_mem, &mem->pub_key_hash, mem);
414
415 if (0 == GNUNET_CONTAINER_multihashmap_size (grp_mem))
416 {
417 GNUNET_CONTAINER_multihashmap_remove (group_members, &grp->pub_key_hash,
418 grp_mem);
419 GNUNET_CONTAINER_multihashmap_destroy (grp_mem);
420 }
421 if (NULL != mem->join_dcsn)
422 {
423 GNUNET_free (mem->join_dcsn);
424 mem->join_dcsn = NULL;
425 }
426 if (NULL != mem->origin_channel)
427 {
428 GNUNET_CADET_channel_destroy (mem->origin_channel->channel);
429 mem->origin_channel = NULL;
430 }
431 GNUNET_CONTAINER_multihashmap_remove (members, &grp->pub_key_hash, mem);
432 GNUNET_free (mem);
433}
434
435
436/**
437 * Clean up group data structures after a client disconnected.
438 */
439static void
440cleanup_group (struct Group *grp)
441{
442 (GNUNET_YES == grp->is_origin)
443 ? cleanup_origin (grp->origin)
444 : cleanup_member (grp->member);
445}
446
447
448void
449replay_key_hash (uint64_t fragment_id, uint64_t message_id,
450 uint64_t fragment_offset, uint64_t flags,
451 struct GNUNET_HashCode *key_hash)
452{
453 struct ReplayRequestKey key = {
454 .fragment_id = fragment_id,
455 .message_id = message_id,
456 .fragment_offset = fragment_offset,
457 .flags = flags,
458 };
459 GNUNET_CRYPTO_hash (&key, sizeof (key), key_hash);
460}
461
462
463/**
464 * Remove channel from replay request hashmap.
465 *
466 * @param chn
467 * Channel to remove.
468 *
469 * @return #GNUNET_YES if there are more entries to process,
470 * #GNUNET_NO when reached end of hashmap.
471 */
472static int
473replay_req_remove_cadet (struct Channel *chn)
474{
475 if (NULL == chn || NULL == chn->group)
476 return GNUNET_SYSERR;
477
478 struct GNUNET_CONTAINER_MultiHashMap *
479 grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet,
480 &chn->group->pub_key_hash);
481 if (NULL == grp_replay_req)
482 return GNUNET_NO;
483
484 struct GNUNET_CONTAINER_MultiHashMapIterator *
485 it = GNUNET_CONTAINER_multihashmap_iterator_create (grp_replay_req);
486 struct GNUNET_HashCode key;
487 const struct Channel *c;
488 while (GNUNET_YES
489 == GNUNET_CONTAINER_multihashmap_iterator_next (it, &key,
490 (const void **) &c))
491 {
492 if (c == chn)
493 {
494 GNUNET_CONTAINER_multihashmap_remove (grp_replay_req, &key, chn);
495 GNUNET_CONTAINER_multihashmap_iterator_destroy (it);
496 return GNUNET_YES;
497 }
498 }
499 GNUNET_CONTAINER_multihashmap_iterator_destroy (it);
500 return GNUNET_NO;
501}
502
503
504/**
505 * Remove client from replay request hashmap.
506 *
507 * @param client
508 * Client to remove.
509 *
510 * @return #GNUNET_YES if there are more entries to process,
511 * #GNUNET_NO when reached end of hashmap.
512 */
513static int
514replay_req_remove_client (struct Group *grp, struct GNUNET_SERVICE_Client *client)
515{
516 struct GNUNET_CONTAINER_MultiHashMap *
517 grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_client,
518 &grp->pub_key_hash);
519 if (NULL == grp_replay_req)
520 return GNUNET_NO;
521
522 struct GNUNET_CONTAINER_MultiHashMapIterator *
523 it = GNUNET_CONTAINER_multihashmap_iterator_create (grp_replay_req);
524 struct GNUNET_HashCode key;
525 const struct GNUNET_SERVICE_Client *c;
526 while (GNUNET_YES
527 == GNUNET_CONTAINER_multihashmap_iterator_next (it, &key,
528 (const void **) &c))
529 {
530 if (c == client)
531 {
532 GNUNET_CONTAINER_multihashmap_remove (grp_replay_req, &key, client);
533 GNUNET_CONTAINER_multihashmap_iterator_destroy (it);
534 return GNUNET_YES;
535 }
536 }
537 GNUNET_CONTAINER_multihashmap_iterator_destroy (it);
538 return GNUNET_NO;
539}
540
541
542/**
543 * Send message to a client.
544 */
545static void
546client_send (struct GNUNET_SERVICE_Client *client,
547 const struct GNUNET_MessageHeader *msg)
548{
549 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
550 "%p Sending message to client.\n", client);
551
552 struct GNUNET_MQ_Envelope *
553 env = GNUNET_MQ_msg_copy (msg);
554
555 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
556 env);
557}
558
559
560/**
561 * Send message to all clients connected to the group.
562 */
563static void
564client_send_group_keep_envelope (const struct Group *grp,
565 struct GNUNET_MQ_Envelope *env)
566{
567 struct ClientList *cli = grp->clients_head;
568
569 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
570 "%p Sending message to all clients of the group.\n",
571 grp);
572 while (NULL != cli)
573 {
574 GNUNET_MQ_send_copy (GNUNET_SERVICE_client_get_mq (cli->client),
575 env);
576 cli = cli->next;
577 }
578}
579
580
581/**
582 * Send message to all clients connected to the group and
583 * takes care of freeing @env.
584 */
585static void
586client_send_group (const struct Group *grp,
587 struct GNUNET_MQ_Envelope *env)
588{
589 client_send_group_keep_envelope (grp, env);
590 GNUNET_MQ_discard (env);
591}
592
593
594/**
595 * Iterator callback for sending a message to origin clients.
596 */
597static int
598client_send_origin_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash,
599 void *origin)
600{
601 struct GNUNET_MQ_Envelope *env = cls;
602 struct Member *orig = origin;
603
604 client_send_group_keep_envelope (&orig->group, env);
605 return GNUNET_YES;
606}
607
608
609/**
610 * Iterator callback for sending a message to member clients.
611 */
612static int
613client_send_member_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash,
614 void *member)
615{
616 struct GNUNET_MQ_Envelope *env = cls;
617 struct Member *mem = member;
618
619 if (NULL != mem->join_dcsn)
620 { /* Only send message to admitted members */
621 client_send_group_keep_envelope (&mem->group, env);
622 }
623 return GNUNET_YES;
624}
625
626
627/**
628 * Send message to all origin and member clients connected to the group.
629 *
630 * @param pub_key_hash
631 * H(key_pub) of the group.
632 * @param msg
633 * Message to send.
634 */
635static int
636client_send_all (struct GNUNET_HashCode *pub_key_hash,
637 struct GNUNET_MQ_Envelope *env)
638{
639 int n = 0;
640 n += GNUNET_CONTAINER_multihashmap_get_multiple (origins, pub_key_hash,
641 client_send_origin_cb,
642 (void *) env);
643 n += GNUNET_CONTAINER_multihashmap_get_multiple (members, pub_key_hash,
644 client_send_member_cb,
645 (void *) env);
646 GNUNET_MQ_discard (env);
647 return n;
648}
649
650
651/**
652 * Send message to a random origin client or a random member client.
653 *
654 * @param grp The group to send @a msg to.
655 * @param msg Message to send.
656 */
657static int
658client_send_random (struct GNUNET_HashCode *pub_key_hash,
659 struct GNUNET_MQ_Envelope *env)
660{
661 int n = 0;
662 n = GNUNET_CONTAINER_multihashmap_get_random (origins, client_send_origin_cb,
663 (void *) env);
664 if (n <= 0)
665 n = GNUNET_CONTAINER_multihashmap_get_random (members, client_send_member_cb,
666 (void *) env);
667 GNUNET_MQ_discard (env);
668 return n;
669}
670
671
672/**
673 * Send message to all origin clients connected to the group.
674 *
675 * @param pub_key_hash
676 * H(key_pub) of the group.
677 * @param msg
678 * Message to send.
679 */
680static int
681client_send_origin (struct GNUNET_HashCode *pub_key_hash,
682 struct GNUNET_MQ_Envelope *env)
683{
684 int n = 0;
685 n += GNUNET_CONTAINER_multihashmap_get_multiple (origins, pub_key_hash,
686 client_send_origin_cb,
687 (void *) env);
688 return n;
689}
690
691
692/**
693 * Send fragment acknowledgement to all clients of the channel.
694 *
695 * @param pub_key_hash
696 * H(key_pub) of the group.
697 */
698static void
699client_send_ack (struct GNUNET_HashCode *pub_key_hash)
700{
701 struct GNUNET_MQ_Envelope *env;
702
703 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
704 "Sending message ACK to client.\n");
705 env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_FRAGMENT_ACK);
706 client_send_all (pub_key_hash, env);
707}
708
709
710struct CadetTransmitClosure
711{
712 struct Channel *chn;
713 const struct GNUNET_MessageHeader *msg;
714};
715
716
717/**
718 * Send a message to a CADET channel.
719 *
720 * @param chn Channel.
721 * @param msg Message.
722 */
723static void
724cadet_send_channel (struct Channel *chn, const struct GNUNET_MessageHeader *msg)
725{
726 struct GNUNET_MQ_Envelope *
727 env = GNUNET_MQ_msg_copy (msg);
728
729 GNUNET_MQ_send (GNUNET_CADET_get_mq (chn->channel), env);
730
731 if (0 < chn->window_size)
732 {
733 client_send_ack (&chn->group_pub_hash);
734 }
735 else
736 {
737 chn->msgs_pending++;
738 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
739 "%p Queuing message. Pending messages: %u\n",
740 chn, chn->msgs_pending);
741 }
742}
743
744
745/**
746 * Create CADET channel and send a join request.
747 */
748static void
749cadet_send_join_request (struct Member *mem)
750{
751 mem->origin_channel = cadet_channel_create (&mem->group, &mem->origin);
752 cadet_send_channel (mem->origin_channel, &mem->join_req->header);
753
754 uint32_t i;
755 for (i = 0; i < mem->relay_count; i++)
756 {
757 struct Channel *
758 chn = cadet_channel_create (&mem->group, &mem->relays[i]);
759 cadet_send_channel (chn, &mem->join_req->header);
760 }
761}
762
763
764static int
765cadet_send_join_decision_cb (void *cls,
766 const struct GNUNET_HashCode *group_pub_hash,
767 void *channel)
768{
769 const struct MulticastJoinDecisionMessageHeader *hdcsn = cls;
770 struct Channel *chn = channel;
771
772 const struct MulticastJoinDecisionMessage *dcsn =
773 (struct MulticastJoinDecisionMessage *) &hdcsn[1];
774
775 if (0 == memcmp (&hdcsn->member_pub_key, &chn->member_pub_key, sizeof (chn->member_pub_key))
776 && 0 == memcmp (&hdcsn->peer, &chn->peer, sizeof (chn->peer)))
777 {
778 if (GNUNET_YES == ntohl (dcsn->is_admitted))
779 {
780 chn->join_status = JOIN_ADMITTED;
781 }
782 else
783 {
784 chn->join_status = JOIN_REFUSED;
785 }
786 cadet_send_channel (chn, &hdcsn->header);
787 return GNUNET_YES;
788 }
789
790 // return GNUNET_YES to continue the multihashmap_get iteration
791 return GNUNET_YES;
792}
793
794
795/**
796 * Send join decision to a remote peer.
797 */
798static void
799cadet_send_join_decision (struct Group *grp,
800 const struct MulticastJoinDecisionMessageHeader *hdcsn)
801{
802 GNUNET_CONTAINER_multihashmap_get_multiple (channels_in, &grp->pub_key_hash,
803 &cadet_send_join_decision_cb,
804 (void *) hdcsn);
805}
806
807
808/**
809 * Iterator callback for sending a message to origin clients.
810 */
811static int
812cadet_send_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash,
813 void *channel)
814{
815 const struct GNUNET_MessageHeader *msg = cls;
816 struct Channel *chn = channel;
817 if (JOIN_ADMITTED == chn->join_status)
818 cadet_send_channel (chn, msg);
819 return GNUNET_YES;
820}
821
822
823/**
824 * Send message to all connected children.
825 */
826static int
827cadet_send_children (struct GNUNET_HashCode *pub_key_hash,
828 const struct GNUNET_MessageHeader *msg)
829{
830 int n = 0;
831 if (channels_in != NULL)
832 n += GNUNET_CONTAINER_multihashmap_get_multiple (channels_in, pub_key_hash,
833 cadet_send_cb, (void *) msg);
834 return n;
835}
836
837
838#if 0 // unused as yet
839/**
840 * Send message to all connected parents.
841 */
842static int
843cadet_send_parents (struct GNUNET_HashCode *pub_key_hash,
844 const struct GNUNET_MessageHeader *msg)
845{
846 int n = 0;
847 if (channels_in != NULL)
848 n += GNUNET_CONTAINER_multihashmap_get_multiple (channels_out, pub_key_hash,
849 cadet_send_cb, (void *) msg);
850 return n;
851}
852#endif
853
854
855/**
856 * CADET channel connect handler.
857 *
858 * @see GNUNET_CADET_ConnectEventHandler()
859 */
860static void *
861cadet_notify_connect (void *cls,
862 struct GNUNET_CADET_Channel *channel,
863 const struct GNUNET_PeerIdentity *source)
864{
865 struct Channel *chn = GNUNET_malloc (sizeof (struct Channel));
866 chn->group = cls;
867 chn->channel = channel;
868 chn->direction = DIR_INCOMING;
869 chn->join_status = JOIN_NOT_ASKED;
870
871 GNUNET_CONTAINER_multihashmap_put (channels_in, &chn->group->pub_key_hash, chn,
872 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
873 return chn;
874}
875
876
877/**
878 * CADET window size change handler.
879 *
880 * @see GNUNET_CADET_WindowSizeEventHandler()
881 */
882static void
883cadet_notify_window_change (void *cls,
884 const struct GNUNET_CADET_Channel *channel,
885 int window_size)
886{
887 struct Channel *chn = cls;
888
889 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
890 "%p Window size changed to %d. Pending messages: %u\n",
891 chn, window_size, chn->msgs_pending);
892
893 chn->is_connected = GNUNET_YES;
894 chn->window_size = (int32_t) window_size;
895
896 for (int i = 0; i < window_size; i++)
897 {
898 if (0 < chn->msgs_pending)
899 {
900 client_send_ack (&chn->group_pub_hash);
901 chn->msgs_pending--;
902 }
903 else
904 {
905 break;
906 }
907 }
908}
909
910
911/**
912 * CADET channel disconnect handler.
913 *
914 * @see GNUNET_CADET_DisconnectEventHandler()
915 */
916static void
917cadet_notify_disconnect (void *cls,
918 const struct GNUNET_CADET_Channel *channel)
919{
920 if (NULL == cls)
921 return;
922
923 struct Channel *chn = cls;
924 if (NULL != chn->group)
925 {
926 if (GNUNET_NO == chn->group->is_origin)
927 {
928 struct Member *mem = (struct Member *) chn->group;
929 if (chn == mem->origin_channel)
930 mem->origin_channel = NULL;
931 }
932 }
933
934 int ret;
935 do
936 {
937 ret = replay_req_remove_cadet (chn);
938 }
939 while (GNUNET_YES == ret);
940
941 GNUNET_free (chn);
942}
943
944
945static int
946check_cadet_join_request (void *cls,
947 const struct MulticastJoinRequestMessage *req)
948{
949 struct Channel *chn = cls;
950
951 if (NULL == chn
952 || JOIN_NOT_ASKED != chn->join_status)
953 {
954 return GNUNET_SYSERR;
955 }
956
957 uint16_t size = ntohs (req->header.size);
958 if (size < sizeof (*req))
959 {
960 GNUNET_break_op (0);
961 return GNUNET_SYSERR;
962 }
963 if (ntohl (req->purpose.size) != (size
964 - sizeof (req->header)
965 - sizeof (req->reserved)
966 - sizeof (req->signature)))
967 {
968 GNUNET_break_op (0);
969 return GNUNET_SYSERR;
970 }
971 if (GNUNET_OK !=
972 GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST,
973 &req->purpose, &req->signature,
974 &req->member_pub_key))
975 {
976 GNUNET_break_op (0);
977 return GNUNET_SYSERR;
978 }
979
980 return GNUNET_OK;
981}
982
983
984/**
985 * Incoming join request message from CADET.
986 */
987static void
988handle_cadet_join_request (void *cls,
989 const struct MulticastJoinRequestMessage *req)
990{
991 struct Channel *chn = cls;
992 GNUNET_CADET_receive_done (chn->channel);
993
994 struct GNUNET_HashCode group_pub_hash;
995 GNUNET_CRYPTO_hash (&req->group_pub_key, sizeof (req->group_pub_key), &group_pub_hash);
996 chn->group_pub_key = req->group_pub_key;
997 chn->group_pub_hash = group_pub_hash;
998 chn->member_pub_key = req->member_pub_key;
999 chn->peer = req->peer;
1000 chn->join_status = JOIN_WAITING;
1001
1002 client_send_all (&group_pub_hash,
1003 GNUNET_MQ_msg_copy (&req->header));
1004}
1005
1006
1007static int
1008check_cadet_join_decision (void *cls,
1009 const struct MulticastJoinDecisionMessageHeader *hdcsn)
1010{
1011 uint16_t size = ntohs (hdcsn->header.size);
1012 if (size < sizeof (struct MulticastJoinDecisionMessageHeader) +
1013 sizeof (struct MulticastJoinDecisionMessage))
1014 {
1015 GNUNET_break_op (0);
1016 return GNUNET_SYSERR;
1017 }
1018
1019 struct Channel *chn = cls;
1020 if (NULL == chn)
1021 {
1022 GNUNET_break (0);
1023 return GNUNET_SYSERR;
1024 }
1025 if (NULL == chn->group || GNUNET_NO != chn->group->is_origin)
1026 {
1027 GNUNET_break (0);
1028 return GNUNET_SYSERR;
1029 }
1030 switch (chn->join_status)
1031 {
1032 case JOIN_REFUSED:
1033 return GNUNET_SYSERR;
1034
1035 case JOIN_ADMITTED:
1036 return GNUNET_OK;
1037
1038 case JOIN_NOT_ASKED:
1039 case JOIN_WAITING:
1040 break;
1041 }
1042
1043 return GNUNET_OK;
1044}
1045
1046
1047/**
1048 * Incoming join decision message from CADET.
1049 */
1050static void
1051handle_cadet_join_decision (void *cls,
1052 const struct MulticastJoinDecisionMessageHeader *hdcsn)
1053{
1054 const struct MulticastJoinDecisionMessage *
1055 dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1];
1056
1057 struct Channel *chn = cls;
1058 GNUNET_CADET_receive_done (chn->channel);
1059
1060 // FIXME: do we need to copy chn->peer or compare it with hdcsn->peer?
1061 struct Member *mem = (struct Member *) chn->group;
1062 client_send_join_decision (mem, hdcsn);
1063 if (GNUNET_YES == ntohl (dcsn->is_admitted))
1064 {
1065 chn->join_status = JOIN_ADMITTED;
1066 }
1067 else
1068 {
1069 chn->join_status = JOIN_REFUSED;
1070 cadet_channel_destroy (chn);
1071 }
1072}
1073
1074
1075static int
1076check_cadet_message (void *cls,
1077 const struct GNUNET_MULTICAST_MessageHeader *msg)
1078{
1079 uint16_t size = ntohs (msg->header.size);
1080 if (size < sizeof (*msg))
1081 {
1082 GNUNET_break_op (0);
1083 return GNUNET_SYSERR;
1084 }
1085
1086 struct Channel *chn = cls;
1087 if (NULL == chn)
1088 {
1089 GNUNET_break (0);
1090 return GNUNET_SYSERR;
1091 }
1092 if (ntohl (msg->purpose.size) != (size
1093 - sizeof (msg->header)
1094 - sizeof (msg->hop_counter)
1095 - sizeof (msg->signature)))
1096 {
1097 GNUNET_break_op (0);
1098 return GNUNET_SYSERR;
1099 }
1100 if (GNUNET_OK !=
1101 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE,
1102 &msg->purpose, &msg->signature,
1103 &chn->group_pub_key))
1104 {
1105 GNUNET_break_op (0);
1106 return GNUNET_SYSERR;
1107 }
1108
1109 return GNUNET_OK;
1110}
1111
1112
1113/**
1114 * Incoming multicast message from CADET.
1115 */
1116static void
1117handle_cadet_message (void *cls,
1118 const struct GNUNET_MULTICAST_MessageHeader *msg)
1119{
1120 struct Channel *chn = cls;
1121 GNUNET_CADET_receive_done (chn->channel);
1122 client_send_all (&chn->group_pub_hash,
1123 GNUNET_MQ_msg_copy (&msg->header));
1124}
1125
1126
1127static int
1128check_cadet_request (void *cls,
1129 const struct GNUNET_MULTICAST_RequestHeader *req)
1130{
1131 uint16_t size = ntohs (req->header.size);
1132 if (size < sizeof (*req))
1133 {
1134 GNUNET_break_op (0);
1135 return GNUNET_SYSERR;
1136 }
1137
1138 struct Channel *chn = cls;
1139 if (NULL == chn)
1140 {
1141 GNUNET_break (0);
1142 return GNUNET_SYSERR;
1143 }
1144 if (ntohl (req->purpose.size) != (size
1145 - sizeof (req->header)
1146 - sizeof (req->member_pub_key)
1147 - sizeof (req->signature)))
1148 {
1149 GNUNET_break_op (0);
1150 return GNUNET_SYSERR;
1151 }
1152 if (GNUNET_OK !=
1153 GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST,
1154 &req->purpose, &req->signature,
1155 &req->member_pub_key))
1156 {
1157 GNUNET_break_op (0);
1158 return GNUNET_SYSERR;
1159 }
1160
1161 return GNUNET_OK;
1162}
1163
1164
1165/**
1166 * Incoming multicast request message from CADET.
1167 */
1168static void
1169handle_cadet_request (void *cls,
1170 const struct GNUNET_MULTICAST_RequestHeader *req)
1171{
1172 struct Channel *chn = cls;
1173 GNUNET_CADET_receive_done (chn->channel);
1174 client_send_origin (&chn->group_pub_hash,
1175 GNUNET_MQ_msg_copy (&req->header));
1176}
1177
1178
1179// FIXME: do checks in handle_cadet_replay_request
1180//static int
1181//check_cadet_replay_request (void *cls,
1182// const struct MulticastReplayRequestMessage *req)
1183//{
1184// uint16_t size = ntohs (req->header.size);
1185// if (size < sizeof (*req))
1186// {
1187// GNUNET_break_op (0);
1188// return GNUNET_SYSERR;
1189// }
1190//
1191// struct Channel *chn = cls;
1192// if (NULL == chn)
1193// {
1194// GNUNET_break_op (0);
1195// return GNUNET_SYSERR;
1196// }
1197//
1198// return GNUNET_OK;
1199//}
1200
1201
1202/**
1203 * Incoming multicast replay request from CADET.
1204 */
1205static void
1206handle_cadet_replay_request (void *cls,
1207 const struct MulticastReplayRequestMessage *req)
1208{
1209 struct Channel *chn = cls;
1210
1211 GNUNET_CADET_receive_done (chn->channel);
1212
1213 struct MulticastReplayRequestMessage rep = *req;
1214 GNUNET_memcpy (&rep.member_pub_key, &chn->member_pub_key, sizeof (chn->member_pub_key));
1215
1216 struct GNUNET_CONTAINER_MultiHashMap *
1217 grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet,
1218 &chn->group->pub_key_hash);
1219 if (NULL == grp_replay_req)
1220 {
1221 grp_replay_req = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1222 GNUNET_CONTAINER_multihashmap_put (replay_req_cadet,
1223 &chn->group->pub_key_hash, grp_replay_req,
1224 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1225 }
1226 struct GNUNET_HashCode key_hash;
1227 replay_key_hash (rep.fragment_id,
1228 rep.message_id,
1229 rep.fragment_offset,
1230 rep.flags,
1231 &key_hash);
1232 GNUNET_CONTAINER_multihashmap_put (grp_replay_req, &key_hash, chn,
1233 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1234
1235 client_send_random (&chn->group_pub_hash,
1236 GNUNET_MQ_msg_copy (&rep.header));
1237}
1238
1239
1240static int
1241check_cadet_replay_response (void *cls,
1242 const struct MulticastReplayResponseMessage *res)
1243{
1244 struct Channel *chn = cls;
1245 if (NULL == chn)
1246 {
1247 GNUNET_break (0);
1248 return GNUNET_SYSERR;
1249 }
1250 return GNUNET_OK;
1251}
1252
1253
1254/**
1255 * Incoming multicast replay response from CADET.
1256 */
1257static void
1258handle_cadet_replay_response (void *cls,
1259 const struct MulticastReplayResponseMessage *res)
1260{
1261 struct Channel *chn = cls;
1262 GNUNET_CADET_receive_done (chn->channel);
1263
1264 /* @todo FIXME: got replay error response, send request to other members */
1265}
1266
1267
1268static void
1269group_set_cadet_port_hash (struct Group *grp)
1270{
1271 struct CadetPort {
1272 struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
1273 uint32_t app_type;
1274 } port = {
1275 grp->pub_key,
1276 GNUNET_APPLICATION_TYPE_MULTICAST,
1277 };
1278 GNUNET_CRYPTO_hash (&port, sizeof (port), &grp->cadet_port_hash);
1279}
1280
1281
1282
1283/**
1284 * Create new outgoing CADET channel.
1285 *
1286 * @param peer
1287 * Peer to connect to.
1288 * @param group_pub_key
1289 * Public key of group the channel belongs to.
1290 * @param group_pub_hash
1291 * Hash of @a group_pub_key.
1292 *
1293 * @return Channel.
1294 */
1295static struct Channel *
1296cadet_channel_create (struct Group *grp, struct GNUNET_PeerIdentity *peer)
1297{
1298 struct Channel *chn = GNUNET_malloc (sizeof (*chn));
1299 chn->group = grp;
1300 chn->group_pub_key = grp->pub_key;
1301 chn->group_pub_hash = grp->pub_key_hash;
1302 chn->peer = *peer;
1303 chn->direction = DIR_OUTGOING;
1304 chn->is_connected = GNUNET_NO;
1305 chn->join_status = JOIN_WAITING;
1306
1307 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1308 GNUNET_MQ_hd_var_size (cadet_message,
1309 GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
1310 struct GNUNET_MULTICAST_MessageHeader,
1311 chn),
1312
1313 GNUNET_MQ_hd_var_size (cadet_join_decision,
1314 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION,
1315 struct MulticastJoinDecisionMessageHeader,
1316 chn),
1317
1318 GNUNET_MQ_hd_fixed_size (cadet_replay_request,
1319 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST,
1320 struct MulticastReplayRequestMessage,
1321 chn),
1322
1323 GNUNET_MQ_hd_var_size (cadet_replay_response,
1324 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE,
1325 struct MulticastReplayResponseMessage,
1326 chn),
1327
1328 GNUNET_MQ_handler_end ()
1329 };
1330
1331 chn->channel = GNUNET_CADET_channel_create (cadet, chn, &chn->peer,
1332 &grp->cadet_port_hash,
1333 GNUNET_CADET_OPTION_RELIABLE,
1334 cadet_notify_window_change,
1335 cadet_notify_disconnect,
1336 cadet_handlers);
1337 GNUNET_CONTAINER_multihashmap_put (channels_out, &chn->group_pub_hash, chn,
1338 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1339 return chn;
1340}
1341
1342
1343/**
1344 * Destroy outgoing CADET channel.
1345 */
1346static void
1347cadet_channel_destroy (struct Channel *chn)
1348{
1349 GNUNET_CADET_channel_destroy (chn->channel);
1350 GNUNET_CONTAINER_multihashmap_remove_all (channels_out, &chn->group_pub_hash);
1351 GNUNET_free (chn);
1352}
1353
1354/**
1355 * Handle a connecting client starting an origin.
1356 */
1357static void
1358handle_client_origin_start (void *cls,
1359 const struct MulticastOriginStartMessage *msg)
1360{
1361 struct Client *c = cls;
1362 struct GNUNET_SERVICE_Client *client = c->client;
1363
1364 struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
1365 struct GNUNET_HashCode pub_key_hash;
1366
1367 GNUNET_CRYPTO_eddsa_key_get_public (&msg->group_key, &pub_key);
1368 GNUNET_CRYPTO_hash (&pub_key, sizeof (pub_key), &pub_key_hash);
1369
1370 struct Origin *
1371 orig = GNUNET_CONTAINER_multihashmap_get (origins, &pub_key_hash);
1372 struct Group *grp;
1373
1374 if (NULL == orig)
1375 {
1376 orig = GNUNET_new (struct Origin);
1377 orig->priv_key = msg->group_key;
1378 orig->max_fragment_id = GNUNET_ntohll (msg->max_fragment_id);
1379
1380 grp = c->group = &orig->group;
1381 grp->origin = orig;
1382 grp->is_origin = GNUNET_YES;
1383 grp->pub_key = pub_key;
1384 grp->pub_key_hash = pub_key_hash;
1385 grp->is_disconnected = GNUNET_NO;
1386
1387 GNUNET_CONTAINER_multihashmap_put (origins, &grp->pub_key_hash, orig,
1388 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1389
1390 group_set_cadet_port_hash (grp);
1391
1392 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1393 GNUNET_MQ_hd_var_size (cadet_message,
1394 GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
1395 struct GNUNET_MULTICAST_MessageHeader,
1396 grp),
1397
1398 GNUNET_MQ_hd_var_size (cadet_request,
1399 GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST,
1400 struct GNUNET_MULTICAST_RequestHeader,
1401 grp),
1402
1403 GNUNET_MQ_hd_var_size (cadet_join_request,
1404 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST,
1405 struct MulticastJoinRequestMessage,
1406 grp),
1407
1408 GNUNET_MQ_hd_fixed_size (cadet_replay_request,
1409 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST,
1410 struct MulticastReplayRequestMessage,
1411 grp),
1412
1413 GNUNET_MQ_hd_var_size (cadet_replay_response,
1414 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE,
1415 struct MulticastReplayResponseMessage,
1416 grp),
1417
1418 GNUNET_MQ_handler_end ()
1419 };
1420
1421
1422 orig->cadet_port = GNUNET_CADET_open_port (cadet,
1423 &grp->cadet_port_hash,
1424 cadet_notify_connect,
1425 grp,
1426 cadet_notify_window_change,
1427 cadet_notify_disconnect,
1428 cadet_handlers);
1429 }
1430 else
1431 {
1432 grp = &orig->group;
1433 }
1434
1435 struct ClientList *cl = GNUNET_new (struct ClientList);
1436 cl->client = client;
1437 GNUNET_CONTAINER_DLL_insert (grp->clients_head, grp->clients_tail, cl);
1438
1439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1440 "%p Client connected as origin to group %s.\n",
1441 orig, GNUNET_h2s (&grp->pub_key_hash));
1442 GNUNET_SERVICE_client_continue (client);
1443}
1444
1445
1446static int
1447check_client_member_join (void *cls,
1448 const struct MulticastMemberJoinMessage *msg)
1449{
1450 uint16_t msg_size = ntohs (msg->header.size);
1451 struct GNUNET_PeerIdentity *relays = (struct GNUNET_PeerIdentity *) &msg[1];
1452 uint32_t relay_count = ntohl (msg->relay_count);
1453
1454 if (0 != relay_count)
1455 {
1456 if (UINT32_MAX / relay_count < sizeof (*relays)){
1457 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1458 "relay_count (%lu) * sizeof (*relays) (%lu) exceeds UINT32_MAX!\n",
1459 (unsigned long)relay_count,
1460 sizeof (*relays));
1461 return GNUNET_SYSERR;
1462 }
1463 }
1464 uint32_t relay_size = relay_count * sizeof (*relays);
1465 struct GNUNET_MessageHeader *join_msg = NULL;
1466 uint16_t join_msg_size = 0;
1467 if (sizeof (*msg) + relay_size + sizeof (struct GNUNET_MessageHeader)
1468 <= msg_size)
1469 {
1470 join_msg = (struct GNUNET_MessageHeader *)
1471 (((char *) &msg[1]) + relay_size);
1472 join_msg_size = ntohs (join_msg->size);
1473 if (UINT16_MAX - join_msg_size < sizeof (struct MulticastJoinRequestMessage)){
1474 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1475 "join_msg_size (%u) + sizeof (struct MulticastJoinRequestMessage) (%lu) exceeds UINT16_MAX!\n",
1476 (unsigned)join_msg_size,
1477 (unsigned long)sizeof (struct MulticastJoinRequestMessage));
1478 return GNUNET_SYSERR;
1479 }
1480 }
1481 if (msg_size != (sizeof (*msg) + relay_size + join_msg_size)){
1482 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1483 "msg_size does not match real size of message!\n");
1484 return GNUNET_SYSERR;
1485 }else{
1486 return GNUNET_OK;
1487 }
1488}
1489
1490
1491/**
1492 * Handle a connecting client joining a group.
1493 */
1494static void
1495handle_client_member_join (void *cls,
1496 const struct MulticastMemberJoinMessage *msg)
1497{
1498 struct Client *c = cls;
1499 struct GNUNET_SERVICE_Client *client = c->client;
1500
1501 uint16_t msg_size = ntohs (msg->header.size);
1502
1503 struct GNUNET_CRYPTO_EcdsaPublicKey mem_pub_key;
1504 struct GNUNET_HashCode pub_key_hash, mem_pub_key_hash;
1505
1506 GNUNET_CRYPTO_ecdsa_key_get_public (&msg->member_key, &mem_pub_key);
1507 GNUNET_CRYPTO_hash (&mem_pub_key, sizeof (mem_pub_key), &mem_pub_key_hash);
1508 GNUNET_CRYPTO_hash (&msg->group_pub_key, sizeof (msg->group_pub_key), &pub_key_hash);
1509
1510 struct GNUNET_CONTAINER_MultiHashMap *
1511 grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members, &pub_key_hash);
1512 struct Member *mem = NULL;
1513 struct Group *grp;
1514
1515 if (NULL != grp_mem)
1516 {
1517 mem = GNUNET_CONTAINER_multihashmap_get (grp_mem, &mem_pub_key_hash);
1518 }
1519
1520 if (NULL == mem)
1521 {
1522 mem = GNUNET_new (struct Member);
1523 mem->origin = msg->origin;
1524 mem->priv_key = msg->member_key;
1525 mem->pub_key = mem_pub_key;
1526 mem->pub_key_hash = mem_pub_key_hash;
1527 mem->max_fragment_id = 0; // FIXME
1528
1529 grp = c->group = &mem->group;
1530 grp->member = mem;
1531 grp->is_origin = GNUNET_NO;
1532 grp->pub_key = msg->group_pub_key;
1533 grp->pub_key_hash = pub_key_hash;
1534 grp->is_disconnected = GNUNET_NO;
1535 group_set_cadet_port_hash (grp);
1536
1537 if (NULL == grp_mem)
1538 {
1539 grp_mem = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
1540 GNUNET_CONTAINER_multihashmap_put (group_members, &grp->pub_key_hash, grp_mem,
1541 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1542 }
1543 GNUNET_CONTAINER_multihashmap_put (grp_mem, &mem->pub_key_hash, mem,
1544 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1545
1546 // FIXME: should the members hash map have option UNIQUE_FAST?
1547 GNUNET_CONTAINER_multihashmap_put (members, &grp->pub_key_hash, mem,
1548 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1549 }
1550 else
1551 {
1552 grp = &mem->group;
1553 }
1554
1555 struct ClientList *cl = GNUNET_new (struct ClientList);
1556 cl->client = client;
1557 GNUNET_CONTAINER_DLL_insert (grp->clients_head, grp->clients_tail, cl);
1558
1559 char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&mem->pub_key);
1560 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1561 "Client connected to group %s as member %s (%s). size = %d\n",
1562 GNUNET_h2s (&grp->pub_key_hash),
1563 GNUNET_h2s2 (&mem->pub_key_hash),
1564 str,
1565 GNUNET_CONTAINER_multihashmap_size (members));
1566 GNUNET_free (str);
1567
1568 if (NULL != mem->join_dcsn)
1569 { /* Already got a join decision, send it to client. */
1570 struct GNUNET_MQ_Envelope *
1571 env = GNUNET_MQ_msg_copy (&mem->join_dcsn->header);
1572
1573 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
1574 env);
1575 }
1576 else
1577 { /* First client of the group, send join request. */
1578 struct GNUNET_PeerIdentity *relays = (struct GNUNET_PeerIdentity *) &msg[1];
1579 uint32_t relay_count = ntohl (msg->relay_count);
1580 uint16_t relay_size = relay_count * sizeof (*relays);
1581 struct GNUNET_MessageHeader *join_msg = NULL;
1582 uint16_t join_msg_size = 0;
1583 if (sizeof (*msg) + relay_size + sizeof (struct GNUNET_MessageHeader)
1584 <= msg_size)
1585 {
1586 join_msg = (struct GNUNET_MessageHeader *)
1587 (((char *) &msg[1]) + relay_size);
1588 join_msg_size = ntohs (join_msg->size);
1589 }
1590
1591 uint16_t req_msg_size = sizeof (struct MulticastJoinRequestMessage) + join_msg_size;
1592 struct MulticastJoinRequestMessage *
1593 req = GNUNET_malloc (req_msg_size);
1594 req->header.size = htons (req_msg_size);
1595 req->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST);
1596 req->group_pub_key = grp->pub_key;
1597 req->peer = this_peer;
1598 GNUNET_CRYPTO_ecdsa_key_get_public (&mem->priv_key, &req->member_pub_key);
1599 if (0 < join_msg_size)
1600 GNUNET_memcpy (&req[1], join_msg, join_msg_size);
1601
1602 req->member_pub_key = mem->pub_key;
1603 req->purpose.size = htonl (req_msg_size
1604 - sizeof (req->header)
1605 - sizeof (req->reserved)
1606 - sizeof (req->signature));
1607 req->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST);
1608
1609 if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (&mem->priv_key, &req->purpose,
1610 &req->signature))
1611 {
1612 /* FIXME: handle error */
1613 GNUNET_assert (0);
1614 }
1615
1616 if (NULL != mem->join_req)
1617 GNUNET_free (mem->join_req);
1618 mem->join_req = req;
1619
1620 if (0 ==
1621 client_send_origin (&grp->pub_key_hash,
1622 GNUNET_MQ_msg_copy (&mem->join_req->header)))
1623 { /* No local origins, send to remote origin */
1624 cadet_send_join_request (mem);
1625 }
1626 }
1627 GNUNET_SERVICE_client_continue (client);
1628}
1629
1630
1631static void
1632client_send_join_decision (struct Member *mem,
1633 const struct MulticastJoinDecisionMessageHeader *hdcsn)
1634{
1635 client_send_group (&mem->group, GNUNET_MQ_msg_copy (&hdcsn->header));
1636
1637 const struct MulticastJoinDecisionMessage *
1638 dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1];
1639 if (GNUNET_YES == ntohl (dcsn->is_admitted))
1640 { /* Member admitted, store join_decision. */
1641 uint16_t dcsn_size = ntohs (dcsn->header.size);
1642 mem->join_dcsn = GNUNET_malloc (dcsn_size);
1643 GNUNET_memcpy (mem->join_dcsn, dcsn, dcsn_size);
1644 }
1645 else
1646 { /* Refused entry, but replay would be still possible for past members. */
1647 }
1648}
1649
1650
1651static int
1652check_client_join_decision (void *cls,
1653 const struct MulticastJoinDecisionMessageHeader *hdcsn)
1654{
1655 return GNUNET_OK;
1656}
1657
1658
1659/**
1660 * Join decision from client.
1661 */
1662static void
1663handle_client_join_decision (void *cls,
1664 const struct MulticastJoinDecisionMessageHeader *hdcsn)
1665{
1666 struct Client *c = cls;
1667 struct GNUNET_SERVICE_Client *client = c->client;
1668 struct Group *grp = c->group;
1669
1670 if (NULL == grp)
1671 {
1672 GNUNET_break (0);
1673 GNUNET_SERVICE_client_drop (client);
1674 return;
1675 }
1676 GNUNET_assert (GNUNET_NO == grp->is_disconnected);
1677 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1678 "%p got join decision from client for group %s..\n",
1679 grp, GNUNET_h2s (&grp->pub_key_hash));
1680
1681 struct GNUNET_CONTAINER_MultiHashMap *
1682 grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members,
1683 &grp->pub_key_hash);
1684 struct Member *mem = NULL;
1685 if (NULL != grp_mem)
1686 {
1687 struct GNUNET_HashCode member_key_hash;
1688 GNUNET_CRYPTO_hash (&hdcsn->member_pub_key, sizeof (hdcsn->member_pub_key),
1689 &member_key_hash);
1690 mem = GNUNET_CONTAINER_multihashmap_get (grp_mem, &member_key_hash);
1691 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1692 "%p ..and member %s: %p\n",
1693 grp, GNUNET_h2s (&member_key_hash), mem);
1694 }
1695
1696 if (NULL != mem)
1697 { /* Found local member */
1698 client_send_join_decision (mem, hdcsn);
1699 }
1700 else
1701 { /* Look for remote member */
1702 cadet_send_join_decision (grp, hdcsn);
1703 }
1704 GNUNET_SERVICE_client_continue (client);
1705}
1706
1707
1708static void
1709handle_client_part_request (void *cls,
1710 const struct GNUNET_MessageHeader *msg)
1711{
1712 struct Client *c = cls;
1713 struct GNUNET_SERVICE_Client *client = c->client;
1714 struct Group *grp = c->group;
1715 struct GNUNET_MQ_Envelope *env;
1716
1717 if (NULL == grp)
1718 {
1719 GNUNET_break (0);
1720 GNUNET_SERVICE_client_drop (client);
1721 return;
1722 }
1723 GNUNET_assert (GNUNET_NO == grp->is_disconnected);
1724 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1725 "%p got part request from client for group %s.\n",
1726 grp, GNUNET_h2s (&grp->pub_key_hash));
1727 grp->is_disconnected = GNUNET_YES;
1728 env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_PART_ACK);
1729 client_send_group (grp, env);
1730 GNUNET_SERVICE_client_continue (client);
1731}
1732
1733
1734static int
1735check_client_multicast_message (void *cls,
1736 const struct GNUNET_MULTICAST_MessageHeader *msg)
1737{
1738 return GNUNET_OK;
1739}
1740
1741
1742/**
1743 * Incoming message from a client.
1744 */
1745static void
1746handle_client_multicast_message (void *cls,
1747 const struct GNUNET_MULTICAST_MessageHeader *msg)
1748{
1749 // FIXME: what if GNUNET_YES == grp->is_disconnected? Do we allow sending messages?
1750 struct Client *c = cls;
1751 struct GNUNET_SERVICE_Client *client = c->client;
1752 struct Group *grp = c->group;
1753
1754 if (NULL == grp)
1755 {
1756 GNUNET_break (0);
1757 GNUNET_SERVICE_client_drop (client);
1758 return;
1759 }
1760 GNUNET_assert (GNUNET_YES == grp->is_origin);
1761 struct Origin *orig = grp->origin;
1762
1763 // FIXME: use GNUNET_MQ_msg_copy
1764 /* FIXME: yucky, should use separate message structs for P2P and CS! */
1765 struct GNUNET_MULTICAST_MessageHeader *
1766 out = (struct GNUNET_MULTICAST_MessageHeader *) GNUNET_copy_message (&msg->header);
1767 out->fragment_id = GNUNET_htonll (++orig->max_fragment_id);
1768 out->purpose.size = htonl (ntohs (out->header.size)
1769 - sizeof (out->header)
1770 - sizeof (out->hop_counter)
1771 - sizeof (out->signature));
1772 out->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE);
1773
1774 if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign (&orig->priv_key, &out->purpose,
1775 &out->signature))
1776 {
1777 GNUNET_assert (0);
1778 }
1779
1780 client_send_all (&grp->pub_key_hash, GNUNET_MQ_msg_copy (&out->header));
1781 cadet_send_children (&grp->pub_key_hash, &out->header);
1782 client_send_ack (&grp->pub_key_hash);
1783 GNUNET_free (out);
1784
1785 GNUNET_SERVICE_client_continue (client);
1786}
1787
1788
1789static int
1790check_client_multicast_request (void *cls,
1791 const struct GNUNET_MULTICAST_RequestHeader *req)
1792{
1793 return GNUNET_OK;
1794}
1795
1796
1797/**
1798 * Incoming request from a client.
1799 */
1800static void
1801handle_client_multicast_request (void *cls,
1802 const struct GNUNET_MULTICAST_RequestHeader *req)
1803{
1804 struct Client *c = cls;
1805 struct GNUNET_SERVICE_Client *client = c->client;
1806 struct Group *grp = c->group;
1807
1808 if (NULL == grp)
1809 {
1810 GNUNET_break (0);
1811 GNUNET_SERVICE_client_drop (client);
1812 return;
1813 }
1814 GNUNET_assert (GNUNET_NO == grp->is_disconnected);
1815 GNUNET_assert (GNUNET_NO == grp->is_origin);
1816 struct Member *mem = grp->member;
1817
1818 /* FIXME: yucky, should use separate message structs for P2P and CS! */
1819 struct GNUNET_MULTICAST_RequestHeader *
1820 out = (struct GNUNET_MULTICAST_RequestHeader *) GNUNET_copy_message (&req->header);
1821 out->member_pub_key = mem->pub_key;
1822 out->fragment_id = GNUNET_ntohll (++mem->max_fragment_id);
1823 out->purpose.size = htonl (ntohs (out->header.size)
1824 - sizeof (out->header)
1825 - sizeof (out->member_pub_key)
1826 - sizeof (out->signature));
1827 out->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST);
1828
1829 if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (&mem->priv_key, &out->purpose,
1830 &out->signature))
1831 {
1832 GNUNET_assert (0);
1833 }
1834
1835 uint8_t send_ack = GNUNET_YES;
1836 if (0 ==
1837 client_send_origin (&grp->pub_key_hash,
1838 GNUNET_MQ_msg_copy (&out->header)))
1839 { /* No local origins, send to remote origin */
1840 if (NULL != mem->origin_channel)
1841 {
1842 cadet_send_channel (mem->origin_channel, &out->header);
1843 send_ack = GNUNET_NO;
1844 }
1845 else
1846 {
1847 /* FIXME: not yet connected to origin */
1848 GNUNET_SERVICE_client_drop (client);
1849 GNUNET_free (out);
1850 return;
1851 }
1852 }
1853 if (GNUNET_YES == send_ack)
1854 {
1855 client_send_ack (&grp->pub_key_hash);
1856 }
1857 GNUNET_free (out);
1858 GNUNET_SERVICE_client_continue (client);
1859}
1860
1861
1862/**
1863 * Incoming replay request from a client.
1864 */
1865static void
1866handle_client_replay_request (void *cls,
1867 const struct MulticastReplayRequestMessage *rep)
1868{
1869 struct Client *c = cls;
1870 struct GNUNET_SERVICE_Client *client = c->client;
1871 struct Group *grp = c->group;
1872
1873 if (NULL == grp)
1874 {
1875 GNUNET_break (0);
1876 GNUNET_SERVICE_client_drop (client);
1877 return;
1878 }
1879 GNUNET_assert (GNUNET_NO == grp->is_disconnected);
1880 GNUNET_assert (GNUNET_NO == grp->is_origin);
1881 struct Member *mem = grp->member;
1882
1883 struct GNUNET_CONTAINER_MultiHashMap *
1884 grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_client,
1885 &grp->pub_key_hash);
1886 if (NULL == grp_replay_req)
1887 {
1888 grp_replay_req = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1889 GNUNET_CONTAINER_multihashmap_put (replay_req_client,
1890 &grp->pub_key_hash, grp_replay_req,
1891 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1892 }
1893
1894 struct GNUNET_HashCode key_hash;
1895 replay_key_hash (rep->fragment_id, rep->message_id, rep->fragment_offset,
1896 rep->flags, &key_hash);
1897 GNUNET_CONTAINER_multihashmap_put (grp_replay_req, &key_hash, client,
1898 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1899
1900 if (0 ==
1901 client_send_origin (&grp->pub_key_hash,
1902 GNUNET_MQ_msg_copy (&rep->header)))
1903 { /* No local origin, replay from remote members / origin. */
1904 if (NULL != mem->origin_channel)
1905 {
1906 cadet_send_channel (mem->origin_channel, &rep->header);
1907 }
1908 else
1909 {
1910 /* FIXME: not yet connected to origin */
1911
1912 GNUNET_assert (0);
1913 GNUNET_SERVICE_client_drop (client);
1914 return;
1915 }
1916 }
1917 GNUNET_SERVICE_client_continue (client);
1918}
1919
1920
1921static int
1922cadet_send_replay_response_cb (void *cls,
1923 const struct GNUNET_HashCode *key_hash,
1924 void *value)
1925{
1926 struct Channel *chn = value;
1927 struct GNUNET_MessageHeader *msg = cls;
1928
1929 cadet_send_channel (chn, msg);
1930 return GNUNET_OK;
1931}
1932
1933
1934static int
1935client_send_replay_response_cb (void *cls,
1936 const struct GNUNET_HashCode *key_hash,
1937 void *value)
1938{
1939 struct GNUNET_SERVICE_Client *client = value;
1940 struct GNUNET_MessageHeader *msg = cls;
1941
1942 client_send (client, msg);
1943 return GNUNET_OK;
1944}
1945
1946
1947static int
1948check_client_replay_response_end (void *cls,
1949 const struct MulticastReplayResponseMessage *res)
1950{
1951 return GNUNET_OK;
1952}
1953
1954
1955/**
1956 * End of replay response from a client.
1957 */
1958static void
1959handle_client_replay_response_end (void *cls,
1960 const struct MulticastReplayResponseMessage *res)
1961{
1962 struct Client *c = cls;
1963 struct GNUNET_SERVICE_Client *client = c->client;
1964 struct Group *grp = c->group;
1965
1966 if (NULL == grp)
1967 {
1968 GNUNET_break (0);
1969 GNUNET_SERVICE_client_drop (client);
1970 return;
1971 }
1972 GNUNET_assert (GNUNET_NO == grp->is_disconnected);
1973
1974 struct GNUNET_HashCode key_hash;
1975 replay_key_hash (res->fragment_id, res->message_id, res->fragment_offset,
1976 res->flags, &key_hash);
1977
1978 struct GNUNET_CONTAINER_MultiHashMap *
1979 grp_replay_req_cadet = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet,
1980 &grp->pub_key_hash);
1981 if (NULL != grp_replay_req_cadet)
1982 {
1983 GNUNET_CONTAINER_multihashmap_remove_all (grp_replay_req_cadet, &key_hash);
1984 }
1985 struct GNUNET_CONTAINER_MultiHashMap *
1986 grp_replay_req_client = GNUNET_CONTAINER_multihashmap_get (replay_req_client,
1987 &grp->pub_key_hash);
1988 if (NULL != grp_replay_req_client)
1989 {
1990 GNUNET_CONTAINER_multihashmap_remove_all (grp_replay_req_client, &key_hash);
1991 }
1992 GNUNET_SERVICE_client_continue (client);
1993}
1994
1995
1996static int
1997check_client_replay_response (void *cls,
1998 const struct MulticastReplayResponseMessage *res)
1999{
2000 const struct GNUNET_MessageHeader *msg;
2001 if (GNUNET_MULTICAST_REC_OK == res->error_code)
2002 {
2003 msg = GNUNET_MQ_extract_nested_mh (res);
2004 if (NULL == msg)
2005 {
2006 return GNUNET_SYSERR;
2007 }
2008 }
2009 return GNUNET_OK;
2010}
2011
2012
2013/**
2014 * Incoming replay response from a client.
2015 *
2016 * Respond with a multicast message on success, or otherwise with an error code.
2017 */
2018static void
2019handle_client_replay_response (void *cls,
2020 const struct MulticastReplayResponseMessage *res)
2021{
2022 struct Client *c = cls;
2023 struct GNUNET_SERVICE_Client *client = c->client;
2024 struct Group *grp = c->group;
2025
2026 if (NULL == grp)
2027 {
2028 GNUNET_break (0);
2029 GNUNET_SERVICE_client_drop (client);
2030 return;
2031 }
2032 GNUNET_assert (GNUNET_NO == grp->is_disconnected);
2033
2034 const struct GNUNET_MessageHeader *msg = &res->header;
2035 if (GNUNET_MULTICAST_REC_OK == res->error_code)
2036 {
2037 msg = GNUNET_MQ_extract_nested_mh (res);
2038 }
2039
2040 struct GNUNET_HashCode key_hash;
2041 replay_key_hash (res->fragment_id, res->message_id, res->fragment_offset,
2042 res->flags, &key_hash);
2043
2044 struct GNUNET_CONTAINER_MultiHashMap *
2045 grp_replay_req_cadet = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet,
2046 &grp->pub_key_hash);
2047 if (NULL != grp_replay_req_cadet)
2048 {
2049 GNUNET_CONTAINER_multihashmap_get_multiple (grp_replay_req_cadet, &key_hash,
2050 cadet_send_replay_response_cb,
2051 (void *) msg);
2052 }
2053 if (GNUNET_MULTICAST_REC_OK == res->error_code)
2054 {
2055 struct GNUNET_CONTAINER_MultiHashMap *
2056 grp_replay_req_client = GNUNET_CONTAINER_multihashmap_get (replay_req_client,
2057 &grp->pub_key_hash);
2058 if (NULL != grp_replay_req_client)
2059 {
2060 GNUNET_CONTAINER_multihashmap_get_multiple (grp_replay_req_client, &key_hash,
2061 client_send_replay_response_cb,
2062 (void *) msg);
2063 }
2064 }
2065 else
2066 {
2067 handle_client_replay_response_end (c, res);
2068 return;
2069 }
2070 GNUNET_SERVICE_client_continue (client);
2071}
2072
2073
2074/**
2075 * A new client connected.
2076 *
2077 * @param cls NULL
2078 * @param client client to add
2079 * @param mq message queue for @a client
2080 * @return @a client
2081 */
2082static void *
2083client_notify_connect (void *cls,
2084 struct GNUNET_SERVICE_Client *client,
2085 struct GNUNET_MQ_Handle *mq)
2086{
2087 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client connected: %p\n", client);
2088 /* FIXME: send connect ACK */
2089
2090 struct Client *c = GNUNET_new (struct Client);
2091 c->client = client;
2092
2093 return c;
2094}
2095
2096
2097/**
2098 * Called whenever a client is disconnected.
2099 * Frees our resources associated with that client.
2100 *
2101 * @param cls closure
2102 * @param client identification of the client
2103 * @param app_ctx must match @a client
2104 */
2105static void
2106client_notify_disconnect (void *cls,
2107 struct GNUNET_SERVICE_Client *client,
2108 void *app_ctx)
2109{
2110 struct Client *c = app_ctx;
2111 struct Group *grp = c->group;
2112 GNUNET_free (c);
2113
2114 if (NULL == grp)
2115 {
2116 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2117 "%p User context is NULL in client_disconnect()\n", grp);
2118 GNUNET_break (0);
2119 return;
2120 }
2121
2122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2123 "%p Client (%s) disconnected from group %s\n",
2124 grp, (GNUNET_YES == grp->is_origin) ? "origin" : "member",
2125 GNUNET_h2s (&grp->pub_key_hash));
2126
2127 // FIXME (due to protocol change): here we must not remove all clients,
2128 // only the one we were notified about!
2129 struct ClientList *cl = grp->clients_head;
2130 while (NULL != cl)
2131 {
2132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2133 "iterating clients for group %p\n",
2134 grp);
2135 if (cl->client == client)
2136 {
2137 GNUNET_CONTAINER_DLL_remove (grp->clients_head, grp->clients_tail, cl);
2138 GNUNET_free (cl);
2139 break;
2140 }
2141 cl = cl->next;
2142 }
2143
2144 while (GNUNET_YES == replay_req_remove_client (grp, client));
2145
2146 if (NULL == grp->clients_head)
2147 { /* Last client disconnected. */
2148 cleanup_group (grp);
2149 }
2150}
2151
2152
2153/**
2154 * Service started.
2155 *
2156 * @param cls closure
2157 * @param server the initialized server
2158 * @param cfg configuration to use
2159 */
2160static void
2161run (void *cls,
2162 const struct GNUNET_CONFIGURATION_Handle *c,
2163 struct GNUNET_SERVICE_Handle *svc)
2164{
2165 cfg = c;
2166 service = svc;
2167 GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer);
2168
2169 stats = GNUNET_STATISTICS_create ("multicast", cfg);
2170 origins = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2171 members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2172 group_members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2173 channels_in = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2174 channels_out = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2175 replay_req_cadet = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2176 replay_req_client = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2177
2178 cadet = GNUNET_CADET_connect (cfg);
2179
2180 GNUNET_assert (NULL != cadet);
2181
2182 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
2183 NULL);
2184}
2185
2186
2187/**
2188 * Define "main" method using service macro.
2189 */
2190GNUNET_SERVICE_MAIN
2191("multicast",
2192 GNUNET_SERVICE_OPTION_NONE,
2193 &run,
2194 &client_notify_connect,
2195 &client_notify_disconnect,
2196 NULL,
2197 GNUNET_MQ_hd_fixed_size (client_origin_start,
2198 GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START,
2199 struct MulticastOriginStartMessage,
2200 NULL),
2201 GNUNET_MQ_hd_var_size (client_member_join,
2202 GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN,
2203 struct MulticastMemberJoinMessage,
2204 NULL),
2205 GNUNET_MQ_hd_var_size (client_join_decision,
2206 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION,
2207 struct MulticastJoinDecisionMessageHeader,
2208 NULL),
2209 GNUNET_MQ_hd_fixed_size (client_part_request,
2210 GNUNET_MESSAGE_TYPE_MULTICAST_PART_REQUEST,
2211 struct GNUNET_MessageHeader,
2212 NULL),
2213 GNUNET_MQ_hd_var_size (client_multicast_message,
2214 GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
2215 struct GNUNET_MULTICAST_MessageHeader,
2216 NULL),
2217 GNUNET_MQ_hd_var_size (client_multicast_request,
2218 GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST,
2219 struct GNUNET_MULTICAST_RequestHeader,
2220 NULL),
2221 GNUNET_MQ_hd_fixed_size (client_replay_request,
2222 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST,
2223 struct MulticastReplayRequestMessage,
2224 NULL),
2225 GNUNET_MQ_hd_var_size (client_replay_response,
2226 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE,
2227 struct MulticastReplayResponseMessage,
2228 NULL),
2229 GNUNET_MQ_hd_var_size (client_replay_response_end,
2230 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE_END,
2231 struct MulticastReplayResponseMessage,
2232 NULL));
2233
2234/* 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 @@
1[multicast]
2START_ON_DEMAND = @START_ON_DEMAND@
3BINARY = gnunet-service-multicast
4
5UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock
6UNIX_MATCH_UID = YES
7UNIX_MATCH_GID = YES
8
9@UNIXONLY@PORT = 2109
10HOSTNAME = localhost
11ACCEPT_FROM = 127.0.0.1;
12ACCEPT_FROM6 = ::1;
13
14# DISABLE_SOCKET_FORWARDING = NO
15# USERNAME =
16# MAXBUF =
17# TIMEOUT =
18# DISABLEV6 =
19# BINDTO =
20# REJECT_FROM =
21# REJECT_FROM6 =
22# 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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19*/
20
21/**
22 * @file multicast/multicast.h
23 * @brief multicast IPC messages
24 * @author Christian Grothoff
25 * @author Gabor X Toth
26 */
27#ifndef MULTICAST_H
28#define MULTICAST_H
29
30#include "platform.h"
31#include "gnunet_multicast_service.h"
32
33GNUNET_NETWORK_STRUCT_BEGIN
34
35
36/**
37 * Header of a join request sent to the origin or another member.
38 */
39struct MulticastJoinRequestMessage
40{
41 /**
42 * Type: GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST
43 */
44 struct GNUNET_MessageHeader header;
45
46 /**
47 * Always zero.
48 */
49 uint32_t reserved;
50
51 /**
52 * ECC signature of the rest of the fields of the join request.
53 *
54 * Signature must match the public key of the joining member.
55 */
56 struct GNUNET_CRYPTO_EcdsaSignature signature;
57
58 /**
59 * Purpose for the signature and size of the signed data.
60 */
61 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
62
63 /**
64 * Public key of the target group.
65 */
66 struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key;
67
68 /**
69 * Public key of the joining member.
70 */
71 struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
72
73 /**
74 * Peer identity of the joining member.
75 */
76 struct GNUNET_PeerIdentity peer;
77
78 /* Followed by struct GNUNET_MessageHeader join_message */
79};
80
81
82/**
83 * Header of a join decision message sent to a peer requesting join.
84 */
85struct MulticastJoinDecisionMessage
86{
87 /**
88 * Type: GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION
89 */
90 struct GNUNET_MessageHeader header;
91
92 /**
93 * #GNUNET_YES if the peer was admitted
94 * #GNUNET_NO if entry was refused,
95 * #GNUNET_SYSERR if the request could not be answered.
96 */
97 int32_t is_admitted;
98
99 /**
100 * Number of relays given.
101 */
102 uint32_t relay_count;
103
104 /* Followed by relay_count peer identities */
105
106 /* Followed by the join response message */
107};
108
109
110/**
111 * Header added to a struct MulticastJoinDecisionMessage
112 * when sent between the client and service.
113 */
114struct MulticastJoinDecisionMessageHeader
115{
116 /**
117 * Type: GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION
118 */
119 struct GNUNET_MessageHeader header;
120
121 /**
122 * C->S: Peer to send the join decision to.
123 * S->C: Peer we received the join decision from.
124 */
125 struct GNUNET_PeerIdentity peer;
126
127 /**
128 * C->S: Public key of the member requesting join.
129 * S->C: Unused.
130 */
131 struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
132
133 /* Followed by struct MulticastJoinDecisionMessage */
134};
135
136
137/**
138 * Message sent from the client to the service to notify the service
139 * about the result of a membership test.
140 */
141struct MulticastMembershipTestResultMessage
142{
143 /**
144 * Type: GNUNET_MESSAGE_TYPE_MULTICAST_MEMBERSHIP_TEST_RESULT
145 */
146 struct GNUNET_MessageHeader header;
147
148 /**
149 * Unique ID that identifies the associated membership test.
150 */
151 uint32_t uid;
152
153 /**
154 * #GNUNET_YES if the peer is a member
155 * #GNUNET_NO if peer is not a member,
156 * #GNUNET_SYSERR if the test could not be answered.
157 */
158 int32_t is_admitted;
159};
160
161
162/**
163 * Message sent from the client to the service OR the service to the
164 * client asking for a message fragment to be replayed.
165 */
166struct MulticastReplayRequestMessage
167{
168
169 /**
170 * The message type should be
171 * #GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST.
172 */
173 struct GNUNET_MessageHeader header;
174
175 /**
176 * S->C: Public key of the member requesting replay.
177 * C->S: Unused.
178 */
179 struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
180
181 /**
182 * ID of the message that is being requested.
183 */
184 uint64_t fragment_id;
185
186 /**
187 * ID of the message that is being requested.
188 */
189 uint64_t message_id;
190
191 /**
192 * Offset of the fragment that is being requested.
193 */
194 uint64_t fragment_offset;
195
196 /**
197 * Additional flags for the request.
198 */
199 uint64_t flags;
200
201 /**
202 * Replay request ID.
203 */
204 uint32_t uid;
205};
206
207
208/**
209 * Message sent from the client to the service to give the service
210 * a replayed message.
211 */
212struct MulticastReplayResponseMessage
213{
214
215 /**
216 * Type: GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE
217 * or GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE_END
218 */
219 struct GNUNET_MessageHeader header;
220
221 /**
222 * ID of the message that is being requested.
223 */
224 uint64_t fragment_id;
225
226 /**
227 * ID of the message that is being requested.
228 */
229 uint64_t message_id;
230
231 /**
232 * Offset of the fragment that is being requested.
233 */
234 uint64_t fragment_offset;
235
236 /**
237 * Additional flags for the request.
238 */
239 uint64_t flags;
240
241 /**
242 * An `enum GNUNET_MULTICAST_ReplayErrorCode` identifying issues (in NBO).
243 */
244 int32_t error_code;
245
246 /* followed by replayed message */
247};
248
249
250/**
251 * Message sent from the client to the service to notify the service
252 * about the starting of a multicast group with this peers as its origin.
253 */
254struct MulticastOriginStartMessage
255{
256 /**
257 * Type: GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START
258 */
259 struct GNUNET_MessageHeader header;
260
261 /**
262 * Always zero.
263 */
264 uint32_t reserved;
265
266 /**
267 * Private, non-ephemeral key for the multicast group.
268 */
269 struct GNUNET_CRYPTO_EddsaPrivateKey group_key;
270
271 /**
272 * Last fragment ID sent to the group, used to continue counting fragments if
273 * we resume operating * a group.
274 */
275 uint64_t max_fragment_id;
276};
277
278
279struct MulticastMemberJoinMessage
280{
281 /**
282 * Type: GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN
283 */
284 struct GNUNET_MessageHeader header;
285
286 uint32_t relay_count GNUNET_PACKED;
287
288 struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key;
289
290 struct GNUNET_CRYPTO_EcdsaPrivateKey member_key;
291
292 struct GNUNET_PeerIdentity origin;
293
294 /* Followed by struct GNUNET_PeerIdentity relays[relay_count] */
295
296 /* Followed by struct GNUNET_MessageHeader join_msg */
297};
298
299
300GNUNET_NETWORK_STRUCT_END
301
302#endif
303/* 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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19*/
20
21/**
22 * @file multicast/multicast_api.c
23 * @brief Multicast service; implements multicast groups using CADET connections.
24 * @author Christian Grothoff
25 * @author Gabor X Toth
26 */
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_multicast_service.h"
31#include "multicast.h"
32
33#define LOG(kind,...) GNUNET_log_from (kind, "multicast-api",__VA_ARGS__)
34
35
36/**
37 * Handle for a request to send a message to all multicast group members
38 * (from the origin).
39 */
40struct GNUNET_MULTICAST_OriginTransmitHandle
41{
42 GNUNET_MULTICAST_OriginTransmitNotify notify;
43 void *notify_cls;
44 struct GNUNET_MULTICAST_Origin *origin;
45
46 uint64_t message_id;
47 uint64_t group_generation;
48 uint64_t fragment_offset;
49};
50
51
52/**
53 * Handle for a message to be delivered from a member to the origin.
54 */
55struct GNUNET_MULTICAST_MemberTransmitHandle
56{
57 GNUNET_MULTICAST_MemberTransmitNotify notify;
58 void *notify_cls;
59 struct GNUNET_MULTICAST_Member *member;
60
61 uint64_t request_id;
62 uint64_t fragment_offset;
63};
64
65
66struct GNUNET_MULTICAST_Group
67{
68 /**
69 * Configuration to use.
70 */
71 const struct GNUNET_CONFIGURATION_Handle *cfg;
72
73 /**
74 * Client connection to the service.
75 */
76 struct GNUNET_MQ_Handle *mq;
77
78 /**
79 * Message to send on connect.
80 */
81 struct GNUNET_MQ_Envelope *connect_env;
82
83 /**
84 * Time to wait until we try to reconnect on failure.
85 */
86 struct GNUNET_TIME_Relative reconnect_delay;
87
88 /**
89 * Task for reconnecting when the listener fails.
90 */
91 struct GNUNET_SCHEDULER_Task *reconnect_task;
92
93 GNUNET_MULTICAST_JoinRequestCallback join_req_cb;
94 GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb;
95 GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb;
96 GNUNET_MULTICAST_MessageCallback message_cb;
97 void *cb_cls;
98
99 /**
100 * Function called after disconnected from the service.
101 */
102 GNUNET_ContinuationCallback disconnect_cb;
103
104 /**
105 * Closure for @a disconnect_cb.
106 */
107 void *disconnect_cls;
108
109 /**
110 * Are we currently transmitting a message?
111 */
112 uint8_t in_transmit;
113
114 /**
115 * Number of MULTICAST_FRAGMENT_ACK messages we are still waiting for.
116 */
117 uint8_t acks_pending;
118
119 /**
120 * Is this the origin or a member?
121 */
122 uint8_t is_origin;
123
124 /**
125 * Is this channel in the process of disconnecting from the service?
126 * #GNUNET_YES or #GNUNET_NO
127 */
128 uint8_t is_disconnecting;
129};
130
131
132/**
133 * Handle for the origin of a multicast group.
134 */
135struct GNUNET_MULTICAST_Origin
136{
137 struct GNUNET_MULTICAST_Group grp;
138 struct GNUNET_MULTICAST_OriginTransmitHandle tmit;
139
140 GNUNET_MULTICAST_RequestCallback request_cb;
141};
142
143
144/**
145 * Handle for a multicast group member.
146 */
147struct GNUNET_MULTICAST_Member
148{
149 struct GNUNET_MULTICAST_Group grp;
150 struct GNUNET_MULTICAST_MemberTransmitHandle tmit;
151
152 GNUNET_MULTICAST_JoinDecisionCallback join_dcsn_cb;
153
154 /**
155 * Replay fragment -> struct GNUNET_MULTICAST_MemberReplayHandle *
156 */
157 struct GNUNET_CONTAINER_MultiHashMap *replay_reqs;
158
159 uint64_t next_fragment_id;
160};
161
162
163/**
164 * Handle that identifies a join request.
165 *
166 * Used to match calls to #GNUNET_MULTICAST_JoinRequestCallback to the
167 * corresponding calls to #GNUNET_MULTICAST_join_decision().
168 */
169struct GNUNET_MULTICAST_JoinHandle
170{
171 struct GNUNET_MULTICAST_Group *group;
172
173 /**
174 * Public key of the member requesting join.
175 */
176 struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
177
178 /**
179 * Peer identity of the member requesting join.
180 */
181 struct GNUNET_PeerIdentity peer;
182};
183
184
185/**
186 * Opaque handle to a replay request from the multicast service.
187 */
188struct GNUNET_MULTICAST_ReplayHandle
189{
190 struct GNUNET_MULTICAST_Group *grp;
191 struct MulticastReplayRequestMessage req;
192};
193
194
195/**
196 * Handle for a replay request.
197 */
198struct GNUNET_MULTICAST_MemberReplayHandle
199{
200};
201
202
203static void
204origin_to_all (struct GNUNET_MULTICAST_Origin *orig);
205
206static void
207member_to_origin (struct GNUNET_MULTICAST_Member *mem);
208
209
210/**
211 * Check join request message.
212 */
213static int
214check_group_join_request (void *cls,
215 const struct MulticastJoinRequestMessage *jreq)
216{
217 uint16_t size = ntohs (jreq->header.size);
218
219 if (sizeof (*jreq) == size)
220 return GNUNET_OK;
221
222 if (sizeof (*jreq) + sizeof (struct GNUNET_MessageHeader) <= size)
223 return GNUNET_OK;
224
225 return GNUNET_SYSERR;
226}
227
228
229/**
230 * Receive join request from service.
231 */
232static void
233handle_group_join_request (void *cls,
234 const struct MulticastJoinRequestMessage *jreq)
235{
236 struct GNUNET_MULTICAST_Group *grp = cls;
237 struct GNUNET_MULTICAST_JoinHandle *jh;
238 const struct GNUNET_MessageHeader *jmsg = NULL;
239
240 if (NULL == grp)
241 {
242 GNUNET_break (0);
243 return;
244 }
245 if (NULL == grp->join_req_cb)
246 return;
247
248 if (sizeof (*jreq) + sizeof (*jmsg) <= ntohs (jreq->header.size))
249 jmsg = (const struct GNUNET_MessageHeader *) &jreq[1];
250
251 jh = GNUNET_malloc (sizeof (*jh));
252 jh->group = grp;
253 jh->member_pub_key = jreq->member_pub_key;
254 jh->peer = jreq->peer;
255 grp->join_req_cb (grp->cb_cls, &jreq->member_pub_key, jmsg, jh);
256
257 grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
258}
259
260
261/**
262 * Check multicast message.
263 */
264static int
265check_group_message (void *cls,
266 const struct GNUNET_MULTICAST_MessageHeader *mmsg)
267{
268 return GNUNET_OK;
269}
270
271
272/**
273 * Receive multicast message from service.
274 */
275static void
276handle_group_message (void *cls,
277 const struct GNUNET_MULTICAST_MessageHeader *mmsg)
278{
279 struct GNUNET_MULTICAST_Group *grp = cls;
280
281 if (GNUNET_YES == grp->is_disconnecting)
282 return;
283
284 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
285 "Calling message callback with a message of size %u.\n",
286 ntohs (mmsg->header.size));
287
288 if (NULL != grp->message_cb)
289 grp->message_cb (grp->cb_cls, mmsg);
290
291 grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
292}
293
294
295/**
296 * Receive message/request fragment acknowledgement from service.
297 */
298static void
299handle_group_fragment_ack (void *cls,
300 const struct GNUNET_MessageHeader *msg)
301{
302 struct GNUNET_MULTICAST_Group *grp = cls;
303
304 LOG (GNUNET_ERROR_TYPE_DEBUG,
305 "%p Got fragment ACK. in_transmit=%u, acks_pending=%u\n",
306 grp, grp->in_transmit, grp->acks_pending);
307
308 if (0 == grp->acks_pending)
309 {
310 LOG (GNUNET_ERROR_TYPE_DEBUG,
311 "%p Ignoring extraneous fragment ACK.\n", grp);
312 return;
313 }
314 grp->acks_pending--;
315
316 if (GNUNET_YES != grp->in_transmit)
317 return;
318
319 if (GNUNET_YES == grp->is_origin)
320 origin_to_all ((struct GNUNET_MULTICAST_Origin *) grp);
321 else
322 member_to_origin ((struct GNUNET_MULTICAST_Member *) grp);
323
324 grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
325}
326
327
328/**
329 * Check unicast request.
330 */
331static int
332check_origin_request (void *cls,
333 const struct GNUNET_MULTICAST_RequestHeader *req)
334{
335 return GNUNET_OK;
336}
337
338
339/**
340 * Origin receives unicast request from a member.
341 */
342static void
343handle_origin_request (void *cls,
344 const struct GNUNET_MULTICAST_RequestHeader *req)
345{
346 struct GNUNET_MULTICAST_Group *grp;
347 struct GNUNET_MULTICAST_Origin *orig = cls;
348 grp = &orig->grp;
349
350 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
351 "Calling request callback with a request of size %u.\n",
352 ntohs (req->header.size));
353
354 if (NULL != orig->request_cb)
355 orig->request_cb (grp->cb_cls, req);
356
357 grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
358}
359
360
361/**
362 * Receive multicast replay request from service.
363 */
364static void
365handle_group_replay_request (void *cls,
366 const struct MulticastReplayRequestMessage *rep)
367
368{
369 struct GNUNET_MULTICAST_Group *grp = cls;
370
371 if (GNUNET_YES == grp->is_disconnecting)
372 return;
373
374 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got replay request.\n");
375
376 if (0 != rep->fragment_id)
377 {
378 if (NULL != grp->replay_frag_cb)
379 {
380 struct GNUNET_MULTICAST_ReplayHandle * rh = GNUNET_malloc (sizeof (*rh));
381 rh->grp = grp;
382 rh->req = *rep;
383 grp->replay_frag_cb (grp->cb_cls, &rep->member_pub_key,
384 GNUNET_ntohll (rep->fragment_id),
385 GNUNET_ntohll (rep->flags), rh);
386 }
387 }
388 else if (0 != rep->message_id)
389 {
390 if (NULL != grp->replay_msg_cb)
391 {
392 struct GNUNET_MULTICAST_ReplayHandle * rh = GNUNET_malloc (sizeof (*rh));
393 rh->grp = grp;
394 rh->req = *rep;
395 grp->replay_msg_cb (grp->cb_cls, &rep->member_pub_key,
396 GNUNET_ntohll (rep->message_id),
397 GNUNET_ntohll (rep->fragment_offset),
398 GNUNET_ntohll (rep->flags), rh);
399 }
400 }
401
402 grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
403}
404
405
406/**
407 * Check replay response.
408 */
409static int
410check_member_replay_response (void *cls,
411 const struct MulticastReplayResponseMessage *res)
412{
413 uint16_t size = ntohs (res->header.size);
414
415 if (sizeof (*res) == size)
416 return GNUNET_OK;
417
418 if (sizeof (*res) + sizeof (struct GNUNET_MULTICAST_MessageHeader) <= size)
419 return GNUNET_OK;
420
421 return GNUNET_SYSERR;
422}
423
424
425/**
426 * Receive replay response from service.
427 */
428static void
429handle_member_replay_response (void *cls,
430 const struct MulticastReplayResponseMessage *res)
431{
432 struct GNUNET_MULTICAST_Group *grp;
433 struct GNUNET_MULTICAST_Member *mem = cls;
434 grp = &mem->grp;
435
436 if (GNUNET_YES == grp->is_disconnecting)
437 return;
438
439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got replay response.\n");
440
441 // FIXME: return result
442}
443
444
445/**
446 * Check join decision.
447 */
448static int
449check_member_join_decision (void *cls,
450 const struct MulticastJoinDecisionMessageHeader *hdcsn)
451{
452 return GNUNET_OK; // checked in handle below
453}
454
455
456/**
457 * Member receives join decision.
458 */
459static void
460handle_member_join_decision (void *cls,
461 const struct MulticastJoinDecisionMessageHeader *hdcsn)
462{
463 struct GNUNET_MULTICAST_Group *grp;
464 struct GNUNET_MULTICAST_Member *mem = cls;
465 grp = &mem->grp;
466
467 const struct MulticastJoinDecisionMessage *
468 dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1];
469
470 uint16_t dcsn_size = ntohs (dcsn->header.size);
471 int is_admitted = ntohl (dcsn->is_admitted);
472
473 LOG (GNUNET_ERROR_TYPE_DEBUG,
474 "%p Member got join decision from multicast: %d\n",
475 mem, is_admitted);
476
477 const struct GNUNET_MessageHeader *join_resp = NULL;
478 uint16_t join_resp_size = 0;
479
480 uint16_t relay_count = ntohl (dcsn->relay_count);
481 const struct GNUNET_PeerIdentity *relays = NULL;
482 uint16_t relay_size = relay_count * sizeof (*relays);
483 if (0 < relay_count)
484 {
485 if (dcsn_size < sizeof (*dcsn) + relay_size)
486 {
487 GNUNET_break_op (0);
488 is_admitted = GNUNET_SYSERR;
489 }
490 else
491 {
492 relays = (struct GNUNET_PeerIdentity *) &dcsn[1];
493 }
494 }
495
496 if (sizeof (*dcsn) + relay_size + sizeof (*join_resp) <= dcsn_size)
497 {
498 join_resp = (const struct GNUNET_MessageHeader *) ((char *) &dcsn[1] + relay_size);
499 join_resp_size = ntohs (join_resp->size);
500 }
501 if (dcsn_size < sizeof (*dcsn) + relay_size + join_resp_size)
502 {
503 LOG (GNUNET_ERROR_TYPE_DEBUG,
504 "Received invalid join decision message from multicast: %u < %u + %u + %u\n",
505 dcsn_size , sizeof (*dcsn), relay_size, join_resp_size);
506 GNUNET_break_op (0);
507 is_admitted = GNUNET_SYSERR;
508 }
509
510 if (NULL != mem->join_dcsn_cb)
511 mem->join_dcsn_cb (grp->cb_cls, is_admitted, &hdcsn->peer,
512 relay_count, relays, join_resp);
513
514 // FIXME:
515 //if (GNUNET_YES != is_admitted)
516 // GNUNET_MULTICAST_member_part (mem);
517
518 grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
519}
520
521
522static void
523group_cleanup (struct GNUNET_MULTICAST_Group *grp)
524{
525 if (NULL != grp->connect_env)
526 {
527 GNUNET_MQ_discard (grp->connect_env);
528 grp->connect_env = NULL;
529 }
530 if (NULL != grp->mq)
531 {
532 GNUNET_MQ_destroy (grp->mq);
533 grp->mq = NULL;
534 }
535 if (NULL != grp->disconnect_cb)
536 {
537 grp->disconnect_cb (grp->disconnect_cls);
538 grp->disconnect_cb = NULL;
539 }
540 GNUNET_free (grp);
541}
542
543
544static void
545handle_group_part_ack (void *cls,
546 const struct GNUNET_MessageHeader *msg)
547{
548 struct GNUNET_MULTICAST_Group *grp = cls;
549
550 group_cleanup (grp);
551}
552
553
554/**
555 * Function to call with the decision made for a join request.
556 *
557 * Must be called once and only once in response to an invocation of the
558 * #GNUNET_MULTICAST_JoinRequestCallback.
559 *
560 * @param join
561 * Join request handle.
562 * @param is_admitted
563 * #GNUNET_YES if the join is approved,
564 * #GNUNET_NO if it is disapproved,
565 * #GNUNET_SYSERR if we cannot answer the request.
566 * @param relay_count
567 * Number of relays given.
568 * @param relays
569 * Array of suggested peers that might be useful relays to use
570 * when joining the multicast group (essentially a list of peers that
571 * are already part of the multicast group and might thus be willing
572 * to help with routing). If empty, only this local peer (which must
573 * be the multicast origin) is a good candidate for building the
574 * multicast tree. Note that it is unnecessary to specify our own
575 * peer identity in this array.
576 * @param join_resp
577 * Message to send in response to the joining peer;
578 * can also be used to redirect the peer to a different group at the
579 * application layer; this response is to be transmitted to the
580 * peer that issued the request even if admission is denied.
581 */
582struct GNUNET_MULTICAST_ReplayHandle *
583GNUNET_MULTICAST_join_decision (struct GNUNET_MULTICAST_JoinHandle *join,
584 int is_admitted,
585 uint16_t relay_count,
586 const struct GNUNET_PeerIdentity *relays,
587 const struct GNUNET_MessageHeader *join_resp)
588{
589 struct GNUNET_MULTICAST_Group *grp = join->group;
590 uint16_t join_resp_size = (NULL != join_resp) ? ntohs (join_resp->size) : 0;
591 uint16_t relay_size = relay_count * sizeof (*relays);
592
593 struct MulticastJoinDecisionMessageHeader *hdcsn;
594 struct MulticastJoinDecisionMessage *dcsn;
595 struct GNUNET_MQ_Envelope *
596 env = GNUNET_MQ_msg_extra (hdcsn, sizeof (*dcsn) + relay_size + join_resp_size,
597 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION);
598 hdcsn->member_pub_key = join->member_pub_key;
599 hdcsn->peer = join->peer;
600
601 dcsn = (struct MulticastJoinDecisionMessage *) &hdcsn[1];
602 dcsn->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION);
603 dcsn->header.size = htons (sizeof (*dcsn) + relay_size + join_resp_size);
604 dcsn->is_admitted = htonl (is_admitted);
605 dcsn->relay_count = htonl (relay_count);
606 if (0 < relay_size)
607 GNUNET_memcpy (&dcsn[1], relays, relay_size);
608 if (0 < join_resp_size)
609 GNUNET_memcpy (((char *) &dcsn[1]) + relay_size, join_resp, join_resp_size);
610
611 GNUNET_MQ_send (grp->mq, env);
612 GNUNET_free (join);
613 return NULL;
614}
615
616
617/**
618 * Replay a message fragment for the multicast group.
619 *
620 * @param rh
621 * Replay handle identifying which replay operation was requested.
622 * @param msg
623 * Replayed message fragment, NULL if not found / an error occurred.
624 * @param ec
625 * Error code. See enum GNUNET_MULTICAST_ReplayErrorCode
626 * If not #GNUNET_MULTICAST_REC_OK, the replay handle is invalidated.
627 */
628void
629GNUNET_MULTICAST_replay_response (struct GNUNET_MULTICAST_ReplayHandle *rh,
630 const struct GNUNET_MessageHeader *msg,
631 enum GNUNET_MULTICAST_ReplayErrorCode ec)
632{
633 uint8_t msg_size = (NULL != msg) ? ntohs (msg->size) : 0;
634 struct MulticastReplayResponseMessage *res;
635 struct GNUNET_MQ_Envelope *
636 env = GNUNET_MQ_msg_extra (res, msg_size,
637 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE);
638 res->fragment_id = rh->req.fragment_id;
639 res->message_id = rh->req.message_id;
640 res->fragment_offset = rh->req.fragment_offset;
641 res->flags = rh->req.flags;
642 res->error_code = htonl (ec);
643
644 if (GNUNET_MULTICAST_REC_OK == ec)
645 {
646 GNUNET_assert (NULL != msg);
647 GNUNET_memcpy (&res[1], msg, msg_size);
648 }
649
650 GNUNET_MQ_send (rh->grp->mq, env);
651
652 if (GNUNET_MULTICAST_REC_OK != ec)
653 GNUNET_free (rh);
654}
655
656
657/**
658 * Indicate the end of the replay session.
659 *
660 * Invalidates the replay handle.
661 *
662 * @param rh
663 * Replay session to end.
664 */
665void
666GNUNET_MULTICAST_replay_response_end (struct GNUNET_MULTICAST_ReplayHandle *rh)
667{
668 struct MulticastReplayResponseMessage *end;
669 struct GNUNET_MQ_Envelope *
670 env = GNUNET_MQ_msg (end, GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE_END);
671
672 end->fragment_id = rh->req.fragment_id;
673 end->message_id = rh->req.message_id;
674 end->fragment_offset = rh->req.fragment_offset;
675 end->flags = rh->req.flags;
676
677 GNUNET_MQ_send (rh->grp->mq, env);
678 GNUNET_free (rh);
679}
680
681
682/**
683 * Replay a message for the multicast group.
684 *
685 * @param rh
686 * Replay handle identifying which replay operation was requested.
687 * @param notify
688 * Function to call to get the message.
689 * @param notify_cls
690 * Closure for @a notify.
691 */
692void
693GNUNET_MULTICAST_replay_response2 (struct GNUNET_MULTICAST_ReplayHandle *rh,
694 GNUNET_MULTICAST_ReplayTransmitNotify notify,
695 void *notify_cls)
696{
697}
698
699
700static void
701origin_connect (struct GNUNET_MULTICAST_Origin *orig);
702
703
704static void
705origin_reconnect (void *cls)
706{
707 origin_connect (cls);
708}
709
710
711/**
712 * Origin client disconnected from service.
713 *
714 * Reconnect after backoff period.
715 */
716static void
717origin_disconnected (void *cls, enum GNUNET_MQ_Error error)
718{
719 struct GNUNET_MULTICAST_Origin *orig = cls;
720 struct GNUNET_MULTICAST_Group *grp = &orig->grp;
721
722 LOG (GNUNET_ERROR_TYPE_DEBUG,
723 "Origin client disconnected (%d), re-connecting\n",
724 (int) error);
725 if (NULL != grp->mq)
726 {
727 GNUNET_MQ_destroy (grp->mq);
728 grp->mq = NULL;
729 }
730
731 grp->reconnect_task = GNUNET_SCHEDULER_add_delayed (grp->reconnect_delay,
732 origin_reconnect,
733 orig);
734 grp->reconnect_delay = GNUNET_TIME_STD_BACKOFF (grp->reconnect_delay);
735}
736
737
738/**
739 * Connect to service as origin.
740 */
741static void
742origin_connect (struct GNUNET_MULTICAST_Origin *orig)
743{
744 struct GNUNET_MULTICAST_Group *grp = &orig->grp;
745
746 struct GNUNET_MQ_MessageHandler handlers[] = {
747 GNUNET_MQ_hd_var_size (group_message,
748 GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
749 struct GNUNET_MULTICAST_MessageHeader,
750 grp),
751 GNUNET_MQ_hd_var_size (origin_request,
752 GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST,
753 struct GNUNET_MULTICAST_RequestHeader,
754 orig),
755 GNUNET_MQ_hd_fixed_size (group_fragment_ack,
756 GNUNET_MESSAGE_TYPE_MULTICAST_FRAGMENT_ACK,
757 struct GNUNET_MessageHeader,
758 grp),
759 GNUNET_MQ_hd_var_size (group_join_request,
760 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST,
761 struct MulticastJoinRequestMessage,
762 grp),
763 GNUNET_MQ_hd_fixed_size (group_part_ack,
764 GNUNET_MESSAGE_TYPE_MULTICAST_PART_ACK,
765 struct GNUNET_MessageHeader,
766 grp),
767 GNUNET_MQ_hd_fixed_size (group_replay_request,
768 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST,
769 struct MulticastReplayRequestMessage,
770 grp),
771 GNUNET_MQ_handler_end ()
772 };
773
774 grp->mq = GNUNET_CLIENT_connect (grp->cfg, "multicast",
775 handlers, origin_disconnected, orig);
776 GNUNET_assert (NULL != grp->mq);
777 GNUNET_MQ_send_copy (grp->mq, grp->connect_env);
778}
779
780
781/**
782 * Start a multicast group.
783 *
784 * Will advertise the origin in the P2P overlay network under the respective
785 * public key so that other peer can find this peer to join it. Peers that
786 * issue GNUNET_MULTICAST_member_join() can then transmit a join request to
787 * either an existing group member or to the origin. If the joining is
788 * approved, the member is cleared for @e replay and will begin to receive
789 * messages transmitted to the group. If joining is disapproved, the failed
790 * candidate will be given a response. Members in the group can send messages
791 * to the origin (one at a time).
792 *
793 * @param cfg
794 * Configuration to use.
795 * @param priv_key
796 * ECC key that will be used to sign messages for this
797 * multicast session; public key is used to identify the multicast group;
798 * @param max_fragment_id
799 * Maximum fragment ID already sent to the group.
800 * 0 for a new group.
801 * @param join_request_cb
802 * Function called to approve / disapprove joining of a peer.
803 * @param replay_frag_cb
804 * Function that can be called to replay a message fragment.
805 * @param replay_msg_cb
806 * Function that can be called to replay a message.
807 * @param request_cb
808 * Function called with message fragments from group members.
809 * @param message_cb
810 * Function called with the message fragments sent to the
811 * network by GNUNET_MULTICAST_origin_to_all(). These message fragments
812 * should be stored for answering replay requests later.
813 * @param cls
814 * Closure for the various callbacks that follow.
815 *
816 * @return Handle for the origin, NULL on error.
817 */
818struct GNUNET_MULTICAST_Origin *
819GNUNET_MULTICAST_origin_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
820 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv_key,
821 uint64_t max_fragment_id,
822 GNUNET_MULTICAST_JoinRequestCallback join_request_cb,
823 GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb,
824 GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb,
825 GNUNET_MULTICAST_RequestCallback request_cb,
826 GNUNET_MULTICAST_MessageCallback message_cb,
827 void *cls)
828{
829 struct GNUNET_MULTICAST_Origin *orig = GNUNET_malloc (sizeof (*orig));
830 struct GNUNET_MULTICAST_Group *grp = &orig->grp;
831
832 struct MulticastOriginStartMessage *start;
833 grp->connect_env = GNUNET_MQ_msg (start,
834 GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START);
835 start->max_fragment_id = max_fragment_id;
836 start->group_key = *priv_key;
837
838 grp->cfg = cfg;
839 grp->is_origin = GNUNET_YES;
840 grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
841
842 grp->cb_cls = cls;
843 grp->join_req_cb = join_request_cb;
844 grp->replay_frag_cb = replay_frag_cb;
845 grp->replay_msg_cb = replay_msg_cb;
846 grp->message_cb = message_cb;
847
848 orig->request_cb = request_cb;
849
850 origin_connect (orig);
851 return orig;
852}
853
854
855/**
856 * Stop a multicast group.
857 *
858 * @param origin
859 * Multicast group to stop.
860 */
861void
862GNUNET_MULTICAST_origin_stop (struct GNUNET_MULTICAST_Origin *orig,
863 GNUNET_ContinuationCallback stop_cb,
864 void *stop_cls)
865{
866 struct GNUNET_MULTICAST_Group *grp = &orig->grp;
867 struct GNUNET_MQ_Envelope *env;
868
869 grp->is_disconnecting = GNUNET_YES;
870 grp->disconnect_cb = stop_cb;
871 grp->disconnect_cls = stop_cls;
872 env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_PART_REQUEST);
873 GNUNET_MQ_send (grp->mq, env);
874}
875
876
877static void
878origin_to_all (struct GNUNET_MULTICAST_Origin *orig)
879{
880 LOG (GNUNET_ERROR_TYPE_DEBUG, "%p origin_to_all()\n", orig);
881 struct GNUNET_MULTICAST_Group *grp = &orig->grp;
882 struct GNUNET_MULTICAST_OriginTransmitHandle *tmit = &orig->tmit;
883 GNUNET_assert (GNUNET_YES == grp->in_transmit);
884
885 size_t buf_size = GNUNET_MULTICAST_FRAGMENT_MAX_SIZE;
886 struct GNUNET_MULTICAST_MessageHeader *msg;
887 struct GNUNET_MQ_Envelope *
888 env = GNUNET_MQ_msg_extra (msg, buf_size - sizeof(*msg),
889 GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE);
890
891 int ret = tmit->notify (tmit->notify_cls, &buf_size, &msg[1]);
892
893 if (! (GNUNET_YES == ret || GNUNET_NO == ret)
894 || GNUNET_MULTICAST_FRAGMENT_MAX_SIZE < buf_size)
895 {
896 LOG (GNUNET_ERROR_TYPE_ERROR,
897 "%p OriginTransmitNotify() returned error or invalid message size.\n",
898 orig);
899 /* FIXME: handle error */
900 GNUNET_MQ_discard (env);
901 return;
902 }
903
904 if (GNUNET_NO == ret && 0 == buf_size)
905 {
906 LOG (GNUNET_ERROR_TYPE_DEBUG,
907 "%p OriginTransmitNotify() - transmission paused.\n", orig);
908 GNUNET_MQ_discard (env);
909 return; /* Transmission paused. */
910 }
911
912 msg->header.size = htons (sizeof (*msg) + buf_size);
913 msg->message_id = GNUNET_htonll (tmit->message_id);
914 msg->group_generation = tmit->group_generation;
915 msg->fragment_offset = GNUNET_htonll (tmit->fragment_offset);
916 tmit->fragment_offset += sizeof (*msg) + buf_size;
917
918 grp->acks_pending++;
919 GNUNET_MQ_send (grp->mq, env);
920
921 if (GNUNET_YES == ret)
922 grp->in_transmit = GNUNET_NO;
923}
924
925
926/**
927 * Send a message to the multicast group.
928 *
929 * @param orig
930 * Handle to the multicast group.
931 * @param message_id
932 * Application layer ID for the message. Opaque to multicast.
933 * @param group_generation
934 * Group generation of the message.
935 * Documented in struct GNUNET_MULTICAST_MessageHeader.
936 * @param notify
937 * Function to call to get the message.
938 * @param notify_cls
939 * Closure for @a notify.
940 *
941 * @return Message handle on success,
942 * NULL on error (i.e. another request is already pending).
943 */
944struct GNUNET_MULTICAST_OriginTransmitHandle *
945GNUNET_MULTICAST_origin_to_all (struct GNUNET_MULTICAST_Origin *orig,
946 uint64_t message_id,
947 uint64_t group_generation,
948 GNUNET_MULTICAST_OriginTransmitNotify notify,
949 void *notify_cls)
950{
951 struct GNUNET_MULTICAST_Group *grp = &orig->grp;
952 if (GNUNET_YES == grp->in_transmit)
953 return NULL;
954 grp->in_transmit = GNUNET_YES;
955
956 struct GNUNET_MULTICAST_OriginTransmitHandle *tmit = &orig->tmit;
957 tmit->origin = orig;
958 tmit->message_id = message_id;
959 tmit->fragment_offset = 0;
960 tmit->group_generation = group_generation;
961 tmit->notify = notify;
962 tmit->notify_cls = notify_cls;
963
964 origin_to_all (orig);
965 return tmit;
966}
967
968
969/**
970 * Resume message transmission to multicast group.
971 *
972 * @param th
973 * Transmission to cancel.
974 */
975void
976GNUNET_MULTICAST_origin_to_all_resume (struct GNUNET_MULTICAST_OriginTransmitHandle *th)
977{
978 struct GNUNET_MULTICAST_Group *grp = &th->origin->grp;
979 if (0 != grp->acks_pending || GNUNET_YES != grp->in_transmit)
980 return;
981 origin_to_all (th->origin);
982}
983
984
985/**
986 * Cancel request for message transmission to multicast group.
987 *
988 * @param th
989 * Transmission to cancel.
990 */
991void
992GNUNET_MULTICAST_origin_to_all_cancel (struct GNUNET_MULTICAST_OriginTransmitHandle *th)
993{
994 th->origin->grp.in_transmit = GNUNET_NO;
995}
996
997
998static void
999member_connect (struct GNUNET_MULTICAST_Member *mem);
1000
1001
1002static void
1003member_reconnect (void *cls)
1004{
1005 member_connect (cls);
1006}
1007
1008
1009/**
1010 * Member client disconnected from service.
1011 *
1012 * Reconnect after backoff period.
1013 */
1014static void
1015member_disconnected (void *cls, enum GNUNET_MQ_Error error)
1016{
1017 struct GNUNET_MULTICAST_Member *mem = cls;
1018 struct GNUNET_MULTICAST_Group *grp = &mem->grp;
1019
1020 LOG (GNUNET_ERROR_TYPE_DEBUG,
1021 "Member client disconnected (%d), re-connecting\n",
1022 (int) error);
1023 GNUNET_MQ_destroy (grp->mq);
1024 grp->mq = NULL;
1025
1026 grp->reconnect_task = GNUNET_SCHEDULER_add_delayed (grp->reconnect_delay,
1027 member_reconnect,
1028 mem);
1029 grp->reconnect_delay = GNUNET_TIME_STD_BACKOFF (grp->reconnect_delay);
1030}
1031
1032
1033/**
1034 * Connect to service as member.
1035 */
1036static void
1037member_connect (struct GNUNET_MULTICAST_Member *mem)
1038{
1039 struct GNUNET_MULTICAST_Group *grp = &mem->grp;
1040
1041 struct GNUNET_MQ_MessageHandler handlers[] = {
1042 GNUNET_MQ_hd_var_size (group_message,
1043 GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
1044 struct GNUNET_MULTICAST_MessageHeader,
1045 grp),
1046 GNUNET_MQ_hd_fixed_size (group_fragment_ack,
1047 GNUNET_MESSAGE_TYPE_MULTICAST_FRAGMENT_ACK,
1048 struct GNUNET_MessageHeader,
1049 grp),
1050 GNUNET_MQ_hd_var_size (group_join_request,
1051 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST,
1052 struct MulticastJoinRequestMessage,
1053 grp),
1054 GNUNET_MQ_hd_var_size (member_join_decision,
1055 GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION,
1056 struct MulticastJoinDecisionMessageHeader,
1057 mem),
1058 GNUNET_MQ_hd_fixed_size (group_part_ack,
1059 GNUNET_MESSAGE_TYPE_MULTICAST_PART_ACK,
1060 struct GNUNET_MessageHeader,
1061 grp),
1062 GNUNET_MQ_hd_fixed_size (group_replay_request,
1063 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST,
1064 struct MulticastReplayRequestMessage,
1065 grp),
1066 GNUNET_MQ_hd_var_size (member_replay_response,
1067 GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE,
1068 struct MulticastReplayResponseMessage,
1069 mem),
1070 GNUNET_MQ_handler_end ()
1071 };
1072
1073 grp->mq = GNUNET_CLIENT_connect (grp->cfg, "multicast",
1074 handlers, member_disconnected, mem);
1075 GNUNET_assert (NULL != grp->mq);
1076 GNUNET_MQ_send_copy (grp->mq, grp->connect_env);
1077}
1078
1079
1080/**
1081 * Join a multicast group.
1082 *
1083 * The entity joining is always the local peer. Further information about the
1084 * candidate can be provided in the @a join_request message. If the join fails, the
1085 * @a message_cb is invoked with a (failure) response and then with NULL. If
1086 * the join succeeds, outstanding (state) messages and ongoing multicast
1087 * messages will be given to the @a message_cb until the member decides to part
1088 * the group. The @a replay_cb function may be called at any time by the
1089 * multicast service to support relaying messages to other members of the group.
1090 *
1091 * @param cfg
1092 * Configuration to use.
1093 * @param group_key
1094 * ECC public key that identifies the group to join.
1095 * @param member_key
1096 * ECC key that identifies the member
1097 * and used to sign requests sent to the origin.
1098 * @param origin
1099 * Peer ID of the origin to send unicast requsets to. If NULL,
1100 * unicast requests are sent back via multiple hops on the reverse path
1101 * of multicast messages.
1102 * @param relay_count
1103 * Number of peers in the @a relays array.
1104 * @param relays
1105 * Peer identities of members of the group, which serve as relays
1106 * and can be used to join the group at. and send the @a join_request to.
1107 * If empty, the @a join_request is sent directly to the @a origin.
1108 * @param join_msg
1109 * Application-dependent join message to be passed to the peer @a origin.
1110 * @param join_request_cb
1111 * Function called to approve / disapprove joining of a peer.
1112 * @param join_decision_cb
1113 * Function called to inform about the join decision.
1114 * @param replay_frag_cb
1115 * Function that can be called to replay message fragments
1116 * this peer already knows from this group. NULL if this
1117 * client is unable to support replay.
1118 * @param replay_msg_cb
1119 * Function that can be called to replay message fragments
1120 * this peer already knows from this group. NULL if this
1121 * client is unable to support replay.
1122 * @param message_cb
1123 * Function to be called for all message fragments we
1124 * receive from the group, excluding those our @a replay_cb
1125 * already has.
1126 * @param cls
1127 * Closure for callbacks.
1128 *
1129 * @return Handle for the member, NULL on error.
1130 */
1131struct GNUNET_MULTICAST_Member *
1132GNUNET_MULTICAST_member_join (const struct GNUNET_CONFIGURATION_Handle *cfg,
1133 const struct GNUNET_CRYPTO_EddsaPublicKey *group_pub_key,
1134 const struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key,
1135 const struct GNUNET_PeerIdentity *origin,
1136 uint16_t relay_count,
1137 const struct GNUNET_PeerIdentity *relays,
1138 const struct GNUNET_MessageHeader *join_msg,
1139 GNUNET_MULTICAST_JoinRequestCallback join_request_cb,
1140 GNUNET_MULTICAST_JoinDecisionCallback join_decision_cb,
1141 GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb,
1142 GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb,
1143 GNUNET_MULTICAST_MessageCallback message_cb,
1144 void *cls)
1145{
1146 struct GNUNET_MULTICAST_Member *mem = GNUNET_malloc (sizeof (*mem));
1147 struct GNUNET_MULTICAST_Group *grp = &mem->grp;
1148
1149 uint16_t relay_size = relay_count * sizeof (*relays);
1150 uint16_t join_msg_size = (NULL != join_msg) ? ntohs (join_msg->size) : 0;
1151 struct MulticastMemberJoinMessage *join;
1152 grp->connect_env = GNUNET_MQ_msg_extra (join, relay_size + join_msg_size,
1153 GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN);
1154 join->group_pub_key = *group_pub_key;
1155 join->member_key = *member_key;
1156 join->origin = *origin;
1157 join->relay_count = ntohl (relay_count);
1158 if (0 < relay_size)
1159 GNUNET_memcpy (&join[1], relays, relay_size);
1160 if (0 < join_msg_size)
1161 GNUNET_memcpy (((char *) &join[1]) + relay_size, join_msg, join_msg_size);
1162
1163 grp->cfg = cfg;
1164 grp->is_origin = GNUNET_NO;
1165 grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
1166
1167 mem->join_dcsn_cb = join_decision_cb;
1168 grp->join_req_cb = join_request_cb;
1169 grp->replay_frag_cb = replay_frag_cb;
1170 grp->replay_msg_cb = replay_msg_cb;
1171 grp->message_cb = message_cb;
1172 grp->cb_cls = cls;
1173
1174 member_connect (mem);
1175 return mem;
1176}
1177
1178
1179/**
1180 * Part a multicast group.
1181 *
1182 * Disconnects from all group members and invalidates the @a member handle.
1183 *
1184 * An application-dependent part message can be transmitted beforehand using
1185 * #GNUNET_MULTICAST_member_to_origin())
1186 *
1187 * @param member
1188 * Membership handle.
1189 */
1190void
1191GNUNET_MULTICAST_member_part (struct GNUNET_MULTICAST_Member *mem,
1192 GNUNET_ContinuationCallback part_cb,
1193 void *part_cls)
1194{
1195 struct GNUNET_MULTICAST_Group *grp = &mem->grp;
1196 struct GNUNET_MQ_Envelope *env;
1197
1198 mem->join_dcsn_cb = NULL;
1199 grp->join_req_cb = NULL;
1200 grp->message_cb = NULL;
1201 grp->replay_msg_cb = NULL;
1202 grp->replay_frag_cb = NULL;
1203 grp->is_disconnecting = GNUNET_YES;
1204 grp->disconnect_cb = part_cb;
1205 grp->disconnect_cls = part_cls;
1206 env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_PART_REQUEST);
1207 GNUNET_MQ_send (grp->mq, env);
1208}
1209
1210
1211void
1212member_replay_request (struct GNUNET_MULTICAST_Member *mem,
1213 uint64_t fragment_id,
1214 uint64_t message_id,
1215 uint64_t fragment_offset,
1216 uint64_t flags)
1217{
1218 struct MulticastReplayRequestMessage *rep;
1219 struct GNUNET_MQ_Envelope *
1220 env = GNUNET_MQ_msg (rep, GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST);
1221
1222 rep->fragment_id = GNUNET_htonll (fragment_id);
1223 rep->message_id = GNUNET_htonll (message_id);
1224 rep->fragment_offset = GNUNET_htonll (fragment_offset);
1225 rep->flags = GNUNET_htonll (flags);
1226
1227 GNUNET_MQ_send (mem->grp.mq, env);
1228}
1229
1230
1231/**
1232 * Request a fragment to be replayed by fragment ID.
1233 *
1234 * Useful if messages below the @e max_known_fragment_id given when joining are
1235 * needed and not known to the client.
1236 *
1237 * @param member
1238 * Membership handle.
1239 * @param fragment_id
1240 * ID of a message fragment that this client would like to see replayed.
1241 * @param flags
1242 * Additional flags for the replay request.
1243 * It is used and defined by GNUNET_MULTICAST_ReplayFragmentCallback
1244 *
1245 * @return Replay request handle.
1246 */
1247struct GNUNET_MULTICAST_MemberReplayHandle *
1248GNUNET_MULTICAST_member_replay_fragment (struct GNUNET_MULTICAST_Member *mem,
1249 uint64_t fragment_id,
1250 uint64_t flags)
1251{
1252 member_replay_request (mem, fragment_id, 0, 0, flags);
1253 // FIXME: return something useful
1254 return NULL;
1255}
1256
1257
1258/**
1259 * Request a message fragment to be replayed.
1260 *
1261 * Useful if messages below the @e max_known_fragment_id given when joining are
1262 * needed and not known to the client.
1263 *
1264 * @param member
1265 * Membership handle.
1266 * @param message_id
1267 * ID of the message this client would like to see replayed.
1268 * @param fragment_offset
1269 * Offset of the fragment within the message to replay.
1270 * @param flags
1271 * Additional flags for the replay request.
1272 * It is used & defined by GNUNET_MULTICAST_ReplayMessageCallback
1273 *
1274 * @return Replay request handle, NULL on error.
1275 */
1276struct GNUNET_MULTICAST_MemberReplayHandle *
1277GNUNET_MULTICAST_member_replay_message (struct GNUNET_MULTICAST_Member *mem,
1278 uint64_t message_id,
1279 uint64_t fragment_offset,
1280 uint64_t flags)
1281{
1282 member_replay_request (mem, 0, message_id, fragment_offset, flags);
1283 // FIXME: return something useful
1284 return NULL;
1285}
1286
1287
1288static void
1289member_to_origin (struct GNUNET_MULTICAST_Member *mem)
1290{
1291 LOG (GNUNET_ERROR_TYPE_DEBUG, "member_to_origin()\n");
1292 struct GNUNET_MULTICAST_Group *grp = &mem->grp;
1293 struct GNUNET_MULTICAST_MemberTransmitHandle *tmit = &mem->tmit;
1294 GNUNET_assert (GNUNET_YES == grp->in_transmit);
1295
1296 size_t buf_size = GNUNET_MULTICAST_FRAGMENT_MAX_SIZE;
1297 struct GNUNET_MULTICAST_RequestHeader *req;
1298 struct GNUNET_MQ_Envelope *
1299 env = GNUNET_MQ_msg_extra (req, buf_size - sizeof(*req),
1300 GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST);
1301
1302 int ret = tmit->notify (tmit->notify_cls, &buf_size, &req[1]);
1303
1304 if (! (GNUNET_YES == ret || GNUNET_NO == ret)
1305 || GNUNET_MULTICAST_FRAGMENT_MAX_SIZE < buf_size)
1306 {
1307 LOG (GNUNET_ERROR_TYPE_ERROR,
1308 "MemberTransmitNotify() returned error or invalid message size. "
1309 "ret=%d, buf_size=%u\n", ret, buf_size);
1310 /* FIXME: handle error */
1311 GNUNET_MQ_discard (env);
1312 return;
1313 }
1314
1315 if (GNUNET_NO == ret && 0 == buf_size)
1316 {
1317 /* Transmission paused. */
1318 GNUNET_MQ_discard (env);
1319 return;
1320 }
1321
1322 req->header.size = htons (sizeof (*req) + buf_size);
1323 req->request_id = GNUNET_htonll (tmit->request_id);
1324 req->fragment_offset = GNUNET_ntohll (tmit->fragment_offset);
1325 tmit->fragment_offset += sizeof (*req) + buf_size;
1326
1327 GNUNET_MQ_send (grp->mq, env);
1328
1329 if (GNUNET_YES == ret)
1330 grp->in_transmit = GNUNET_NO;
1331}
1332
1333
1334/**
1335 * Send a message to the origin of the multicast group.
1336 *
1337 * @param mem
1338 * Membership handle.
1339 * @param request_id
1340 * Application layer ID for the request. Opaque to multicast.
1341 * @param notify
1342 * Callback to call to get the message.
1343 * @param notify_cls
1344 * Closure for @a notify.
1345 *
1346 * @return Handle to cancel request, NULL on error (i.e. request already pending).
1347 */
1348struct GNUNET_MULTICAST_MemberTransmitHandle *
1349GNUNET_MULTICAST_member_to_origin (struct GNUNET_MULTICAST_Member *mem,
1350 uint64_t request_id,
1351 GNUNET_MULTICAST_MemberTransmitNotify notify,
1352 void *notify_cls)
1353{
1354 if (GNUNET_YES == mem->grp.in_transmit)
1355 return NULL;
1356 mem->grp.in_transmit = GNUNET_YES;
1357
1358 struct GNUNET_MULTICAST_MemberTransmitHandle *tmit = &mem->tmit;
1359 tmit->member = mem;
1360 tmit->request_id = request_id;
1361 tmit->fragment_offset = 0;
1362 tmit->notify = notify;
1363 tmit->notify_cls = notify_cls;
1364
1365 member_to_origin (mem);
1366 return tmit;
1367}
1368
1369
1370/**
1371 * Resume message transmission to origin.
1372 *
1373 * @param th
1374 * Transmission to cancel.
1375 */
1376void
1377GNUNET_MULTICAST_member_to_origin_resume (struct GNUNET_MULTICAST_MemberTransmitHandle *th)
1378{
1379 struct GNUNET_MULTICAST_Group *grp = &th->member->grp;
1380 if (0 != grp->acks_pending || GNUNET_YES != grp->in_transmit)
1381 return;
1382 member_to_origin (th->member);
1383}
1384
1385
1386/**
1387 * Cancel request for message transmission to origin.
1388 *
1389 * @param th
1390 * Transmission to cancel.
1391 */
1392void
1393GNUNET_MULTICAST_member_to_origin_cancel (struct GNUNET_MULTICAST_MemberTransmitHandle *th)
1394{
1395 th->member->grp.in_transmit = GNUNET_NO;
1396}
1397
1398
1399/* 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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file multicast/test_multicast.c
23 * @brief Tests for the Multicast API.
24 * @author Gabor X Toth
25 */
26
27#include <inttypes.h>
28
29#include "platform.h"
30#include "gnunet_crypto_lib.h"
31#include "gnunet_common.h"
32#include "gnunet_util_lib.h"
33#include "gnunet_testing_lib.h"
34#include "gnunet_multicast_service.h"
35
36#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
37
38/**
39 * Return value from 'main'.
40 */
41static int res;
42
43/**
44 * Handle for task for timeout termination.
45 */
46static struct GNUNET_SCHEDULER_Task * end_badly_task;
47
48static const struct GNUNET_CONFIGURATION_Handle *cfg;
49
50struct GNUNET_PeerIdentity this_peer;
51
52struct GNUNET_MULTICAST_Origin *origin;
53struct GNUNET_MULTICAST_Member *member;
54
55struct GNUNET_CRYPTO_EddsaPrivateKey *group_key;
56struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key;
57
58struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key;
59struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
60
61struct TransmitClosure {
62 struct GNUNET_MULTICAST_OriginTransmitHandle *orig_tmit;
63 struct GNUNET_MULTICAST_MemberTransmitHandle *mem_tmit;
64 char * data[16];
65 uint8_t data_delay[16];
66 uint8_t data_count;
67 uint8_t paused;
68 uint8_t n;
69} tmit_cls;
70
71struct OriginClosure {
72 uint8_t msgs_expected;
73 uint8_t n;
74} origin_cls;
75
76struct MemberClosure {
77 uint8_t msgs_expected;
78 size_t n;
79} member_cls;
80
81struct GNUNET_MessageHeader *join_req, *join_resp;
82
83enum
84{
85 TEST_NONE = 0,
86 TEST_ORIGIN_START = 1,
87 TEST_MEMBER_JOIN_REFUSE = 2,
88 TEST_MEMBER_JOIN_ADMIT = 3,
89 TEST_ORIGIN_TO_ALL = 4,
90 TEST_ORIGIN_TO_ALL_RECV = 5,
91 TEST_MEMBER_TO_ORIGIN = 6,
92 TEST_MEMBER_REPLAY_ERROR = 7,
93 TEST_MEMBER_REPLAY_OK = 8,
94 TEST_MEMBER_PART = 9,
95 TEST_ORIGIN_STOP = 10,
96} test;
97
98uint64_t replay_fragment_id;
99uint64_t replay_flags;
100
101static void
102member_join (int t);
103
104
105/**
106 * Clean up all resources used.
107 */
108static void
109cleanup ()
110{
111 if (NULL != member)
112 {
113 GNUNET_MULTICAST_member_part (member, NULL, NULL);
114 member = NULL;
115 }
116 if (NULL != origin)
117 {
118 GNUNET_MULTICAST_origin_stop (origin, NULL, NULL);
119 origin = NULL;
120 }
121}
122
123
124/**
125 * Terminate the test case (failure).
126 *
127 * @param cls NULL
128 */
129static void
130end_badly (void *cls)
131{
132 res = 1;
133 cleanup ();
134 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test FAILED.\n");
135}
136
137
138/**
139 * Terminate the test case (success).
140 *
141 * @param cls NULL
142 */
143static void
144end_normally (void *cls)
145{
146 res = 0;
147 cleanup ();
148 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Test PASSED.\n");
149}
150
151
152/**
153 * Finish the test case (successfully).
154 */
155static void
156end ()
157{
158 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending tests.\n");
159
160 if (end_badly_task != NULL)
161 {
162 GNUNET_SCHEDULER_cancel (end_badly_task);
163 end_badly_task = NULL;
164 }
165 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
166 &end_normally, NULL);
167}
168
169
170static void
171tmit_resume (void *cls)
172{
173 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission resumed.\n");
174 struct TransmitClosure *tmit = cls;
175 if (NULL != tmit->orig_tmit)
176 GNUNET_MULTICAST_origin_to_all_resume (tmit->orig_tmit);
177 else if (NULL != tmit->mem_tmit)
178 GNUNET_MULTICAST_member_to_origin_resume (tmit->mem_tmit);
179}
180
181
182static int
183tmit_notify (void *cls, size_t *data_size, void *data)
184{
185 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
186 "Test #%u: origin_tmit_notify()\n", test);
187 struct TransmitClosure *tmit = cls;
188
189 if (0 == tmit->data_count)
190 {
191 *data_size = 0;
192 return GNUNET_YES;
193 }
194
195 uint16_t size = strlen (tmit->data[tmit->n]);
196 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
197 "Transmit notify data: %u bytes available, processing fragment %u/%u (size %u).\n",
198 (unsigned int) *data_size,
199 tmit->n + 1,
200 tmit->data_count,
201 size);
202 if (*data_size < size)
203 {
204 *data_size = 0;
205 GNUNET_assert (0);
206 return GNUNET_SYSERR;
207 }
208
209 if (GNUNET_YES != tmit->paused && 0 < tmit->data_delay[tmit->n])
210 {
211 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission paused.\n");
212 tmit->paused = GNUNET_YES;
213 GNUNET_SCHEDULER_add_delayed (
214 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
215 tmit->data_delay[tmit->n]),
216 tmit_resume, tmit);
217 *data_size = 0;
218 return GNUNET_NO;
219 }
220 tmit->paused = GNUNET_NO;
221
222 *data_size = size;
223 GNUNET_memcpy (data, tmit->data[tmit->n], size);
224
225 return ++tmit->n < tmit->data_count ? GNUNET_NO : GNUNET_YES;
226}
227
228
229static void
230member_recv_join_request (void *cls,
231 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key,
232 const struct GNUNET_MessageHeader *join_msg,
233 struct GNUNET_MULTICAST_JoinHandle *jh)
234{
235 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
236 "Test #%u: member_recv_join_request()\n", test);
237}
238
239
240static void
241origin_stopped (void *cls)
242{
243 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
244 "Test #%u: origin_stopped()\n", test);
245 end ();
246}
247
248
249static void
250schedule_origin_stop (void *cls)
251{
252 test = TEST_ORIGIN_STOP;
253 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
254 "Test #%u: origin_stop()\n", test);
255 GNUNET_MULTICAST_origin_stop (origin, origin_stopped, NULL);
256 origin = NULL;
257}
258
259
260static void
261member_parted (void *cls)
262{
263 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
264 "Test #%u: member_parted()\n", test);
265 member = NULL;
266
267 switch (test)
268 {
269 case TEST_MEMBER_JOIN_REFUSE:
270 // Test 3 starts here
271 member_join (TEST_MEMBER_JOIN_ADMIT);
272 break;
273
274 case TEST_MEMBER_PART:
275 GNUNET_SCHEDULER_add_now (&schedule_origin_stop, NULL);
276 break;
277
278 default:
279 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
280 "Invalid test #%d in member_parted()\n", test);
281 GNUNET_assert (0);
282 }
283}
284
285
286static void
287schedule_member_part (void *cls)
288{
289 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
290 "Test #%u: schedule_member_part()\n", test);
291 GNUNET_MULTICAST_member_part (member, member_parted, NULL);
292}
293
294
295static void
296member_part ()
297{
298 test = TEST_MEMBER_PART;
299 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
300 "Test #%u: member_part()\n", test);
301 // Test 10 starts here
302 GNUNET_SCHEDULER_add_now (&schedule_member_part, NULL);
303}
304
305
306static void
307member_replay_ok ()
308{
309 // Execution of test 8 here
310 test = TEST_MEMBER_REPLAY_OK;
311 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
312 "Test #%u: member_replay_ok()\n", test);
313 replay_fragment_id = 1;
314 replay_flags = 1 | 1<<11;
315 GNUNET_MULTICAST_member_replay_fragment (member, replay_fragment_id,
316 replay_flags);
317}
318
319
320static void
321member_replay_error ()
322{
323 test = TEST_MEMBER_REPLAY_ERROR;
324 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
325 "Test #%u: member_replay_error()\n", test);
326 replay_fragment_id = 1234;
327 replay_flags = 11 | 1<<11;
328 GNUNET_MULTICAST_member_replay_fragment (member, replay_fragment_id,
329 replay_flags);
330}
331
332
333static void
334origin_recv_replay_msg (void *cls,
335 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key,
336 uint64_t message_id,
337 uint64_t fragment_offset,
338 uint64_t flags,
339 struct GNUNET_MULTICAST_ReplayHandle *rh)
340{
341 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
342 "Test #%u: origin_recv_replay_msg()\n", test);
343 GNUNET_assert (0);
344}
345
346
347static void
348member_recv_replay_msg (void *cls,
349 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key,
350 uint64_t message_id,
351 uint64_t fragment_offset,
352 uint64_t flags,
353 struct GNUNET_MULTICAST_ReplayHandle *rh)
354{
355 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
356 "Test #%u: member_recv_replay_msg()\n", test);
357 GNUNET_assert (0);
358}
359
360
361static void
362origin_recv_replay_frag (void *cls,
363 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key,
364 uint64_t fragment_id,
365 uint64_t flags,
366 struct GNUNET_MULTICAST_ReplayHandle *rh)
367{
368 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
369 "Test #%u: origin_recv_replay_frag()"
370 " - fragment_id=%" PRIu64 " flags=%" PRIu64 "\n",
371 test, fragment_id, flags);
372 GNUNET_assert (replay_fragment_id == fragment_id && replay_flags == flags);
373 switch (test)
374 {
375 case TEST_MEMBER_REPLAY_ERROR:
376 // Test 8 starts here
377 GNUNET_MULTICAST_replay_response (rh, NULL, GNUNET_SYSERR);
378 member_replay_ok ();
379 break;
380
381 case TEST_MEMBER_REPLAY_OK:
382 {
383 struct GNUNET_MULTICAST_MessageHeader mmsg = {
384 .header = {
385 .type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE),
386 .size = htons (sizeof (mmsg)),
387 },
388 .fragment_id = GNUNET_htonll (1),
389 .message_id = GNUNET_htonll (1),
390 .fragment_offset = 0,
391 .group_generation = GNUNET_htonll (1),
392 .flags = 0,
393 };
394 member_cls.n = 0;
395 member_cls.msgs_expected = 1;
396 GNUNET_MULTICAST_replay_response (rh, &mmsg.header, GNUNET_MULTICAST_REC_OK);
397 GNUNET_MULTICAST_replay_response_end (rh);
398 break;
399 }
400
401 default:
402 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
403 "Invalid test #%d in origin_recv_replay_frag()\n", test);
404 GNUNET_assert (0);
405 }
406}
407
408
409static void
410member_recv_replay_frag (void *cls,
411 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key,
412 uint64_t fragment_id,
413 uint64_t flags,
414 struct GNUNET_MULTICAST_ReplayHandle *rh)
415{
416 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
417 "Test #%u: member_recv_replay_frag()\n", test);
418 GNUNET_assert (0);
419}
420
421
422static void
423origin_recv_request (void *cls,
424 const struct GNUNET_MULTICAST_RequestHeader *req)
425{
426 struct OriginClosure *ocls = cls;
427 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
428 "Test #%u: origin_recv_request()\n", test);
429 if (++ocls->n != ocls->msgs_expected)
430 return;
431
432 GNUNET_assert (0 == memcmp (&req->member_pub_key,
433 &member_pub_key, sizeof (member_pub_key)));
434
435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
436 "Test #%u: verify message content, take first 3 bytes: %.3s\n",
437 test, (char *)&req[1]);
438 GNUNET_assert (0 == memcmp (&req[1], "abc", 3));
439
440 // Test 7 starts here
441 member_replay_error ();
442}
443
444
445static void
446member_to_origin ()
447{
448 test = TEST_MEMBER_TO_ORIGIN;
449 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
450 "Test #%u: member_to_origin()\n", test);
451
452 struct TransmitClosure *tmit = &tmit_cls;
453 *tmit = (struct TransmitClosure) {};
454 tmit->data[0] = "abc def";
455 tmit->data[1] = "ghi jkl mno";
456 tmit->data_delay[1] = 2;
457 tmit->data[2] = "pqr stuw xyz";
458 tmit->data_count = 3;
459
460 origin_cls.n = 0;
461 origin_cls.msgs_expected = 1;
462
463 tmit->mem_tmit = GNUNET_MULTICAST_member_to_origin (member, 1,
464 tmit_notify, tmit);
465}
466
467
468static void
469member_recv_message (void *cls,
470 const struct GNUNET_MULTICAST_MessageHeader *msg)
471{
472 struct MemberClosure *mcls = cls;
473
474 // Test 5 starts here after message has been received from origin
475 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
476 "Test #%u: member_recv_message() %u/%u\n",
477 test,
478 (unsigned int) (mcls->n + 1),
479 mcls->msgs_expected);
480 if (++mcls->n != mcls->msgs_expected)
481 return;
482
483 // FIXME: check message content
484
485 switch (test)
486 {
487 case TEST_ORIGIN_TO_ALL:
488 test = TEST_ORIGIN_TO_ALL_RECV;
489 break;
490
491 case TEST_ORIGIN_TO_ALL_RECV:
492 // Test 6 starts here
493 member_to_origin ();
494 break;
495
496 case TEST_MEMBER_REPLAY_OK:
497 // Test 9 starts here
498 GNUNET_assert (replay_fragment_id == GNUNET_ntohll (msg->fragment_id));
499 member_part ();
500 break;
501
502 default:
503 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
504 "Invalid test #%d in origin_recv_message()\n", test);
505 GNUNET_assert (0);
506 }
507}
508
509
510static void
511origin_recv_message (void *cls,
512 const struct GNUNET_MULTICAST_MessageHeader *msg)
513{
514 struct OriginClosure *ocls = cls;
515 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
516 "Test #%u: origin_recv_message() %u/%u\n",
517 test, ocls->n + 1, ocls->msgs_expected);
518 if (++ocls->n != ocls->msgs_expected)
519 return;
520
521 // FIXME: check message content
522
523 switch (test)
524 {
525 case TEST_ORIGIN_TO_ALL:
526 // Prepare to execute test 5
527 test = TEST_ORIGIN_TO_ALL_RECV;
528 break;
529
530 case TEST_ORIGIN_TO_ALL_RECV:
531 // Test 6 starts here
532 member_to_origin ();
533 break;
534
535 default:
536 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
537 "Invalid test #%d in origin_recv_message()\n", test);
538 GNUNET_assert (0);
539 }
540}
541
542
543static void
544origin_to_all ()
545{
546 test = TEST_ORIGIN_TO_ALL;
547 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
548 "Test #%u: origin_to_all()\n", test);
549
550 struct TransmitClosure *tmit = &tmit_cls;
551 *tmit = (struct TransmitClosure) {};
552 tmit->data[0] = "ABC DEF";
553 tmit->data[1] = GNUNET_malloc (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD + 1);
554 uint16_t i;
555 for (i = 0; i < GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD; i++)
556 tmit->data[1][i] = (0 == i % 10000) ? '0' + i / 10000 : '_';
557 tmit->data[2] = "GHI JKL MNO";
558 tmit->data_delay[2] = 2;
559 tmit->data[3] = "PQR STUW XYZ";
560 tmit->data_count = 4;
561
562 origin_cls.n = member_cls.n = 0;
563 origin_cls.msgs_expected = member_cls.msgs_expected = tmit->data_count;
564
565 tmit->orig_tmit = GNUNET_MULTICAST_origin_to_all (origin, 1, 1,
566 tmit_notify, tmit);
567}
568
569
570static void
571member_recv_join_decision (void *cls,
572 int is_admitted,
573 const struct GNUNET_PeerIdentity *peer,
574 uint16_t relay_count,
575 const struct GNUNET_PeerIdentity *relays,
576 const struct GNUNET_MessageHeader *join_msg)
577{
578 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
579 "Test #%u: member_recv_join_decision() - is_admitted: %d\n",
580 test, is_admitted);
581
582 GNUNET_assert (join_msg->size == join_resp->size);
583 GNUNET_assert (join_msg->type == join_resp->type);
584 GNUNET_assert (0 == memcmp (join_msg, join_resp, ntohs (join_resp->size)));
585
586 switch (test)
587 {
588 case TEST_MEMBER_JOIN_REFUSE:
589 GNUNET_assert (0 == relay_count);
590 // Test 3 starts here
591 GNUNET_SCHEDULER_add_now (&schedule_member_part, NULL);
592 break;
593
594 case TEST_MEMBER_JOIN_ADMIT:
595 GNUNET_assert (1 == relay_count);
596 GNUNET_assert (0 == memcmp (relays, &this_peer, sizeof (this_peer)));
597 // Test 4 starts here
598 origin_to_all ();
599 break;
600
601 default:
602 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
603 "Invalid test #%d in member_recv_join_decision()\n", test);
604 GNUNET_assert (0);
605 }
606}
607
608/**
609 * Test: origin receives join request
610 */
611static void
612origin_recv_join_request (void *cls,
613 const struct GNUNET_CRYPTO_EcdsaPublicKey *mem_key,
614 const struct GNUNET_MessageHeader *join_msg,
615 struct GNUNET_MULTICAST_JoinHandle *jh)
616{
617 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
618 "Test #%u: origin_recv_join_request()\n", test);
619
620 GNUNET_assert (0 == memcmp (mem_key, &member_pub_key, sizeof (member_pub_key)));
621 GNUNET_assert (join_msg->size == join_req->size);
622 GNUNET_assert (join_msg->type == join_req->type);
623 GNUNET_assert (0 == memcmp (join_msg, join_req, ntohs (join_req->size)));
624
625 char data[] = "here's the decision";
626 uint8_t data_size = strlen (data) + 1;
627 join_resp = GNUNET_malloc (sizeof (join_resp) + data_size);
628 join_resp->size = htons (sizeof (join_resp) + data_size);
629 join_resp->type = htons (456);
630 GNUNET_memcpy (&join_resp[1], data, data_size);
631
632 switch (test)
633 {
634 case TEST_MEMBER_JOIN_REFUSE:
635 // Test 3 starts here
636 GNUNET_MULTICAST_join_decision (jh, GNUNET_NO, 0, NULL, join_resp);
637 break;
638
639 case TEST_MEMBER_JOIN_ADMIT:
640 // Test 3 is running
641 GNUNET_MULTICAST_join_decision (jh, GNUNET_YES, 1, &this_peer, join_resp);
642 break;
643
644 default:
645 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
646 "Invalid test #%d in origin_recv_join_request()\n", test);
647 GNUNET_assert (0);
648 break;
649 }
650}
651
652/**
653 * Test: member joins multicast group
654 */
655static void
656member_join (int t)
657{
658 test = t;
659 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
660 "Test #%u: member_join()\n", test);
661
662 member_key = GNUNET_CRYPTO_ecdsa_key_create ();
663 GNUNET_CRYPTO_ecdsa_key_get_public (member_key, &member_pub_key);
664
665 if (NULL != join_req)
666 GNUNET_free (join_req);
667
668 char data[] = "let me in!";
669 uint8_t data_size = strlen (data) + 1;
670 join_req = GNUNET_malloc (sizeof (join_req) + data_size);
671 join_req->size = htons (sizeof (join_req) + data_size);
672 join_req->type = htons (123);
673 GNUNET_memcpy (&join_req[1], data, data_size);
674
675 member = GNUNET_MULTICAST_member_join (cfg, &group_pub_key, member_key,
676 &this_peer, 1, &this_peer, join_req,
677 member_recv_join_request,
678 member_recv_join_decision,
679 member_recv_replay_frag,
680 member_recv_replay_msg,
681 member_recv_message,
682 &member_cls);
683}
684
685/**
686 * Test: Start a multicast group as origin
687 */
688static void
689origin_start ()
690{
691 test = TEST_ORIGIN_START;
692 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
693 "Test #%u: origin_start()\n", test);
694
695 group_key = GNUNET_CRYPTO_eddsa_key_create ();
696 GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key);
697
698 origin = GNUNET_MULTICAST_origin_start (cfg, group_key, 0,
699 origin_recv_join_request,
700 origin_recv_replay_frag,
701 origin_recv_replay_msg,
702 origin_recv_request,
703 origin_recv_message,
704 &origin_cls);
705 // Test 2 starts here
706 member_join (TEST_MEMBER_JOIN_REFUSE);
707}
708
709
710/**
711 * Main function of the test, run from scheduler.
712 *
713 * @param cls NULL
714 * @param cfg configuration we use (also to connect to Multicast service)
715 * @param peer handle to access more of the peer (not used)
716 */
717static void
718#if DEBUG_TEST_MULTICAST
719run (void *cls,
720 char *const *args,
721 const char *cfgfile,
722 const struct GNUNET_CONFIGURATION_Handle *c)
723#else
724run (void *cls,
725 const struct GNUNET_CONFIGURATION_Handle *c,
726 struct GNUNET_TESTING_Peer *peer)
727#endif
728{
729 cfg = c;
730 end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
731 &end_badly, NULL);
732 GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer);
733
734 // Test 1 starts here
735 origin_start ();
736}
737
738
739int
740main (int argc, char *argv[])
741{
742 res = 1;
743#if DEBUG_TEST_MULTICAST
744 const struct GNUNET_GETOPT_CommandLineOption opts[] = {
745 GNUNET_GETOPT_OPTION_END
746 };
747 if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-multicast",
748 "test-multicast [options]",
749 opts, &run, NULL))
750 return 1;
751#else
752 if (0 != GNUNET_TESTING_peer_run ("test-multicast", "test_multicast.conf", &run, NULL))
753 return 1;
754#endif
755 return res;
756}
757
758/* 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 @@
1[testbed]
2HOSTNAME = localhost
3
4[arm]
5GLOBAL_POSTFIX=-L ERROR
6
7[multicast]
8#PREFIX = tmux new-window gdb -x ./cmd.gdb --args
9#PREFIX = valgrind --leak-check=full
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock
11
12[vpn]
13START_ON_DEMAND = NO
14
15[peerinfo]
16# Do not use shipped gnunet HELLOs
17USE_INCLUDED_HELLOS = NO
18
19# Option to disable all disk IO; only useful for testbed runs
20# (large-scale experiments); disables persistence of HELLOs!
21NO_IO = YES
22
23[hostlist]
24IMMEDIATE_START = NO
25START_ON_DEMAND = NO
26
27[nat]
28ENABLE_UPNP = NO
29
30[fs]
31IMMEDIATE_START = NO
32START_ON_DEMAND = NO
33
34[vpn]
35IMMEDIATE_START = NO
36START_ON_DEMAND = NO
37
38[revocation]
39IMMEDIATE_START = NO
40START_ON_DEMAND = NO
41
42[gns]
43IMMEDIATE_START = NO
44START_ON_DEMAND = NO
45
46[namestore]
47IMMEDIATE_START = NO
48START_ON_DEMAND = NO
49
50[namecache]
51IMMEDIATE_START = NO
52START_ON_DEMAND = NO
53
54[topology]
55IMMEDIATE_START = NO
56START_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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file multicast/test_multicast_2peers.c
23 * @brief Tests for the Multicast API with two peers doing the ping
24 * pong test.
25 * @author xrs
26 */
27
28#include <inttypes.h>
29
30#include "platform.h"
31#include "gnunet_crypto_lib.h"
32#include "gnunet_common.h"
33#include "gnunet_util_lib.h"
34#include "gnunet_testbed_service.h"
35#include "gnunet_multicast_service.h"
36
37#define NUM_PEERS 2
38
39static struct GNUNET_TESTBED_Operation *op0;
40static struct GNUNET_TESTBED_Operation *op1;
41static struct GNUNET_TESTBED_Operation *pi_op0;
42static struct GNUNET_TESTBED_Operation *pi_op1;
43
44static struct GNUNET_TESTBED_Peer **peers;
45const struct GNUNET_PeerIdentity *peer_id[2];
46
47static struct GNUNET_SCHEDULER_Task *timeout_tid;
48
49static struct GNUNET_MULTICAST_Origin *origin;
50static struct GNUNET_MULTICAST_Member *member;
51
52struct GNUNET_CRYPTO_EddsaPrivateKey *group_key;
53struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key;
54
55struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key;
56struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
57
58/**
59 * Global result for testcase.
60 */
61static int result;
62
63
64/**
65 * Function run on CTRL-C or shutdown (i.e. success/timeout/etc.).
66 * Cleans up.
67 */
68static void
69shutdown_task (void *cls)
70{
71 if (NULL != op0)
72 {
73 GNUNET_TESTBED_operation_done (op0);
74 op0 = NULL;
75 }
76 if (NULL != op1)
77 {
78 GNUNET_TESTBED_operation_done (op1);
79 op1 = NULL;
80 }
81 if (NULL != pi_op0)
82 {
83 GNUNET_TESTBED_operation_done (pi_op0);
84 pi_op0 = NULL;
85 }
86 if (NULL != pi_op1)
87 {
88 GNUNET_TESTBED_operation_done (pi_op1);
89 pi_op1 = NULL;
90 }
91 if (NULL != timeout_tid)
92 {
93 GNUNET_SCHEDULER_cancel (timeout_tid);
94 timeout_tid = NULL;
95 }
96}
97
98
99static void
100timeout_task (void *cls)
101{
102 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
103 "Timeout!\n");
104 result = GNUNET_SYSERR;
105 GNUNET_SCHEDULER_shutdown ();
106}
107
108
109static void
110member_join_request (void *cls,
111 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
112 const struct GNUNET_MessageHeader *join_msg,
113 struct GNUNET_MULTICAST_JoinHandle *jh)
114{
115 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
116 "Member sent a join request.\n");
117
118}
119
120
121static int
122notify (void *cls,
123 size_t *data_size,
124 void *data)
125{
126
127 char text[] = "ping";
128 *data_size = strlen(text)+1;
129 GNUNET_memcpy(data, text, *data_size);
130
131 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
132 "Member sents message to origin: %s\n", text);
133
134 return GNUNET_YES;
135}
136
137
138static void
139member_join_decision (void *cls,
140 int is_admitted,
141 const struct GNUNET_PeerIdentity *peer,
142 uint16_t relay_count,
143 const struct GNUNET_PeerIdentity *relays,
144 const struct GNUNET_MessageHeader *join_msg)
145{
146 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
147 "Member received a decision from origin: %s\n",
148 (GNUNET_YES == is_admitted)
149 ? "accepted"
150 : "rejected");
151
152 if (GNUNET_YES == is_admitted)
153 {
154 struct GNUNET_MULTICAST_MemberTransmitHandle *req;
155
156 // FIXME: move to MQ-style API!
157 req = GNUNET_MULTICAST_member_to_origin (member,
158 0,
159 &notify,
160 NULL);
161 }
162}
163
164
165static void
166member_message (void *cls,
167 const struct GNUNET_MULTICAST_MessageHeader *msg)
168{
169 if (0 != strncmp ("pong", (char *)&msg[1], 4))
170 {
171 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "member did not receive pong\n");
172 result = GNUNET_SYSERR;
173 GNUNET_SCHEDULER_shutdown ();
174 }
175
176 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
177 "member receives: %s\n", (char *)&msg[1]);
178
179 // Testcase ends here.
180 result = GNUNET_YES;
181 GNUNET_SCHEDULER_shutdown ();
182}
183
184
185static void
186origin_join_request (void *cls,
187 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
188 const struct GNUNET_MessageHeader *join_msg,
189 struct GNUNET_MULTICAST_JoinHandle *jh)
190{
191 struct GNUNET_MessageHeader *join_resp;
192
193 uint8_t data_size = ntohs (join_msg->size);
194
195 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
196 "origin got a join request...\n");
197 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
198 "origin receives: '%s'\n", (char *)&join_msg[1]);
199
200 const char data[] = "Come in!";
201 data_size = strlen (data) + 1;
202 join_resp = GNUNET_malloc (sizeof (join_resp) + data_size);
203 join_resp->size = htons (sizeof (join_resp) + data_size);
204 join_resp->type = htons (123);
205 GNUNET_memcpy (&join_resp[1], data, data_size);
206
207 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
208 "origin sends: '%s'\n", data);
209
210 GNUNET_MULTICAST_join_decision (jh,
211 GNUNET_YES,
212 0,
213 NULL,
214 join_resp);
215 GNUNET_free (join_resp);
216 result = GNUNET_OK;
217}
218
219
220int
221origin_notify (void *cls,
222 size_t *data_size,
223 void *data)
224{
225 char text[] = "pong";
226
227 *data_size = strlen(text)+1;
228 GNUNET_memcpy (data,
229 text,
230 *data_size);
231
232 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin sends (to all): %s\n", text);
233
234 return GNUNET_YES;
235}
236
237
238static void
239origin_request (void *cls,
240 const struct GNUNET_MULTICAST_RequestHeader *req)
241{
242 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin receives: %s\n", (char *)&req[1]);
243
244 if (0 != strncmp ("ping", (char *)&req[1], 4))
245 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "origin didn't reveice a correct request");
246
247 GNUNET_MULTICAST_origin_to_all (origin,
248 0,
249 0,
250 origin_notify,
251 NULL);
252}
253
254
255static void
256origin_message (void *cls,
257 const struct GNUNET_MULTICAST_MessageHeader *msg)
258{
259 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin message msg\n");
260}
261
262
263static void
264service_connect1 (void *cls,
265 struct GNUNET_TESTBED_Operation *op,
266 void *ca_result,
267 const char *emsg)
268{
269 member = ca_result;
270
271 if (NULL == member)
272 {
273 result = GNUNET_SYSERR;
274 GNUNET_SCHEDULER_shutdown ();
275 }
276 else
277 {
278 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to multicast service of member\n");
279 }
280}
281
282
283static void
284multicast_da1 (void *cls,
285 void * op_result)
286{
287 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
288 "Member parting from multicast group\n");
289
290 GNUNET_MULTICAST_member_part (member, NULL, NULL);
291}
292
293
294static void *
295multicast_ca1 (void *cls,
296 const struct GNUNET_CONFIGURATION_Handle *cfg)
297{
298 struct GNUNET_MessageHeader *join_msg;
299 void *ret;
300
301 // Get members keys
302 member_key = GNUNET_CRYPTO_ecdsa_key_create ();
303 GNUNET_CRYPTO_ecdsa_key_get_public (member_key, &member_pub_key);
304
305 char data[] = "Hi, can I enter?";
306 uint8_t data_size = strlen (data) + 1;
307 join_msg = GNUNET_malloc (sizeof (join_msg) + data_size);
308 join_msg->size = htons (sizeof (join_msg) + data_size);
309 join_msg->type = htons (123);
310 GNUNET_memcpy (&join_msg[1], data, data_size);
311
312 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
313 "Members tries to join multicast group\n");
314
315 ret = GNUNET_MULTICAST_member_join (cfg,
316 &group_pub_key,
317 member_key,
318 peer_id[0],
319 0,
320 NULL,
321 join_msg, /* join message */
322 member_join_request,
323 member_join_decision,
324 NULL, /* no test for member_replay_frag */
325 NULL, /* no test for member_replay_msg */
326 member_message,
327 NULL);
328 GNUNET_free (join_msg);
329 return ret;
330}
331
332
333static void
334peer_information_cb (void *cls,
335 struct GNUNET_TESTBED_Operation *op,
336 const struct GNUNET_TESTBED_PeerInformation *pinfo,
337 const char *emsg)
338{
339 int i = (int) (long) cls;
340
341 if (NULL == pinfo)
342 {
343 result = GNUNET_SYSERR;
344 GNUNET_SCHEDULER_shutdown ();
345 }
346
347 peer_id[i] = pinfo->result.id;
348
349 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
350 "Got peer information of %s (%s)\n", (0==i)?"origin":"member" ,GNUNET_i2s(pinfo->result.id));
351
352 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
353 "Create member peer\n");
354
355 if (0 == i)
356 {
357 /* connect to multicast service of member */
358 op1 = GNUNET_TESTBED_service_connect (NULL, /* Closure for operation */
359 peers[1], /* The peer whose service to connect to */
360 "multicast", /* The name of the service */
361 service_connect1, /* callback to call after a handle to service
362 is opened */
363 NULL, /* closure for the above callback */
364 multicast_ca1, /* callback to call with peer's configuration;
365 this should open the needed service connection */
366 multicast_da1, /* callback to be called when closing the
367 opened service connection */
368 NULL); /* closure for the above two callbacks */
369 }
370}
371
372
373/**
374 * Test logic of peer "0" being origin starts here.
375 *
376 * @param cls closure, for the example: NULL
377 * @param op should be equal to "dht_op"
378 * @param ca_result result of the connect operation, the
379 * connection to the DHT service
380 * @param emsg error message, if testbed somehow failed to
381 * connect to the DHT.
382 */
383static void
384service_connect0 (void *cls,
385 struct GNUNET_TESTBED_Operation *op,
386 void *ca_result,
387 const char *emsg)
388{
389 origin = ca_result;
390
391 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
392 "Connected to multicast service of origin\n");
393
394 // Get GNUnet identity of origin
395 pi_op0 = GNUNET_TESTBED_peer_get_information (peers[0],
396 GNUNET_TESTBED_PIT_IDENTITY,
397 peer_information_cb,
398 (void *) 0);
399 // Get GNUnet identity of member
400 pi_op1 = GNUNET_TESTBED_peer_get_information (peers[1],
401 GNUNET_TESTBED_PIT_IDENTITY,
402 peer_information_cb,
403 (void *) 1);
404
405 /* Connection to service successful. Here we'd usually do something with
406 * the service. */
407 result = GNUNET_OK;
408 //GNUNET_SCHEDULER_shutdown (); /* Also kills the testbed */
409}
410
411
412
413/**
414 * Function run when service multicast has started and is providing us
415 * with a configuration file.
416 */
417static void *
418multicast_ca0 (void *cls,
419 const struct GNUNET_CONFIGURATION_Handle *cfg)
420{
421 group_key = GNUNET_CRYPTO_eddsa_key_create ();
422 GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key);
423
424 return GNUNET_MULTICAST_origin_start (cfg,
425 group_key,
426 0,
427 origin_join_request,
428 NULL, /* no test for origin_replay_frag */
429 NULL, /* no test for origin_replay_msg */
430 origin_request,
431 origin_message,
432 NULL);
433}
434
435static void
436multicast_da0 (void *cls,
437 void *op_result)
438{
439 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
440 "Origin closes multicast group\n");
441
442 GNUNET_MULTICAST_origin_stop (origin, NULL, NULL);
443}
444
445
446/**
447 * Main function inovked from TESTBED once all of the
448 * peers are up and running. This one then connects
449 * just to the multicast service of peer 0 and 1.
450 * Peer 0 is going to be origin.
451 * Peer 1 is going to be one member.
452 * Origin will start a multicast group and the member will try to join it.
453 * After that we execute some multicast test.
454 *
455 * @param cls closure
456 * @param h the run handle
457 * @param peers started peers for the test
458 * @param num_peers size of the 'peers' array
459 * @param links_succeeded number of links between peers that were created
460 * @param links_failed number of links testbed was unable to establish
461 */
462static void
463testbed_master (void *cls,
464 struct GNUNET_TESTBED_RunHandle *h,
465 unsigned int num_peers,
466 struct GNUNET_TESTBED_Peer **p,
467 unsigned int links_succeeded,
468 unsigned int links_failed)
469{
470 /* Testbed is ready with peers running and connected in a pre-defined overlay
471 topology (FIXME) */
472 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
473 "Connected to testbed_master()\n");
474
475 peers = p;
476
477 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
478 "Create origin peer\n");
479 op0 = GNUNET_TESTBED_service_connect (NULL, /* Closure for operation */
480 peers[0], /* The peer whose service to connect to */
481 "multicast", /* The name of the service */
482 service_connect0, /* callback to call after a handle to service
483 is opened */
484 NULL, /* closure for the above callback */
485 multicast_ca0, /* callback to call with peer's configuration;
486 this should open the needed service connection */
487 multicast_da0, /* callback to be called when closing the
488 opened service connection */
489 NULL); /* closure for the above two callbacks */
490
491 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); /* Schedule a new task on shutdown */
492
493 /* Schedule the shutdown task with a delay of a few Seconds */
494 timeout_tid = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 50),
495 &timeout_task, NULL);
496}
497
498
499int
500main (int argc, char *argv[])
501{
502 int ret;
503
504 result = GNUNET_SYSERR;
505 ret = GNUNET_TESTBED_test_run
506 ("test-multicast-2peers", /* test case name */
507 "test_multicast.conf", /* template configuration */
508 NUM_PEERS, /* number of peers to start */
509 0LL, /* Event mask - set to 0 for no event notifications */
510 NULL, /* Controller event callback */
511 NULL, /* Closure for controller event callback */
512 testbed_master, /* continuation callback to be called when testbed setup is complete */
513 NULL); /* Closure for the test_master callback */
514 if ( (GNUNET_OK != ret) || (GNUNET_OK != result) )
515 return 1;
516 return 0;
517}
518
519
520/* 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 @@
1[testbed]
2HOSTNAME = localhost
3OVERLAY_TOPOLOGY = LINE
4
5[arm]
6GLOBAL_POSTFIX=-L ERROR
7
8[multicast]
9#PREFIX = tmux new-window gdb -x ./cmd.gdb --args
10#PREFIX = valgrind --leak-check=full
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock
12
13[vpn]
14START_ON_DEMAND = NO
15
16[peerinfo]
17# Do not use shipped gnunet HELLOs
18USE_INCLUDED_HELLOS = NO
19
20# Option to disable all disk IO; only useful for testbed runs
21# (large-scale experiments); disables persistence of HELLOs!
22NO_IO = YES
23
24[cadet]
25ID_ANNOUNCE_TIME = 5 s
26
27[hostlist]
28IMMEDIATE_START = NO
29START_ON_DEMAND = NO
30
31[nat]
32ENABLE_UPNP = NO
33
34[fs]
35IMMEDIATE_START = NO
36START_ON_DEMAND = NO
37
38[vpn]
39IMMEDIATE_START = NO
40START_ON_DEMAND = NO
41
42[revocation]
43IMMEDIATE_START = NO
44START_ON_DEMAND = NO
45
46[gns]
47IMMEDIATE_START = NO
48START_ON_DEMAND = NO
49
50[namestore]
51IMMEDIATE_START = NO
52START_ON_DEMAND = NO
53
54[namecache]
55IMMEDIATE_START = NO
56START_ON_DEMAND = NO
57
58[topology]
59IMMEDIATE_START = NO
60START_ON_DEMAND = NO
61
62[nse]
63WORKBITS = 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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file multicast/test_multicast_multipeers.c
23 * @brief Tests for the Multicast API with multiple peers.
24 * @author xrs
25 */
26
27#include <inttypes.h>
28
29#include "platform.h"
30#include "gnunet_crypto_lib.h"
31#include "gnunet_common.h"
32#include "gnunet_util_lib.h"
33#include "gnunet_testbed_service.h"
34#include "gnunet_multicast_service.h"
35
36#define PEERS_REQUESTED 12
37
38struct MulticastPeerContext
39{
40 int peer; /* peer number */
41 struct GNUNET_CRYPTO_EcdsaPrivateKey *key;
42 const struct GNUNET_PeerIdentity *id;
43 struct GNUNET_TESTBED_Operation *op; /* not yet in use */
44 struct GNUNET_TESTBED_Operation *pi_op; /* not yet in use */
45 int test_ok;
46};
47
48enum pingpong
49{
50 PING = 1,
51 PONG = 2
52};
53
54struct pingpong_msg
55{
56 int peer;
57 enum pingpong msg;
58};
59
60static void service_connect (void *cls,
61 struct GNUNET_TESTBED_Operation *op,
62 void *ca_result,
63 const char *emsg);
64
65static struct MulticastPeerContext **multicast_peers;
66static struct GNUNET_TESTBED_Peer **peers;
67
68static struct GNUNET_TESTBED_Operation *op[PEERS_REQUESTED];
69static struct GNUNET_TESTBED_Operation *pi_op[PEERS_REQUESTED];
70
71static struct GNUNET_MULTICAST_Origin *origin;
72static struct GNUNET_MULTICAST_Member *members[PEERS_REQUESTED]; /* first element always empty */
73
74static struct GNUNET_SCHEDULER_Task *timeout_tid;
75
76static struct GNUNET_CRYPTO_EddsaPrivateKey *group_key;
77static struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key;
78static struct GNUNET_HashCode group_pub_key_hash;
79
80/**
81 * Global result for testcase.
82 */
83static int result;
84
85/**
86 * Function run on CTRL-C or shutdown (i.e. success/timeout/etc.).
87 * Cleans up.
88 */
89static void
90shutdown_task (void *cls)
91{
92 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
93 "shutdown_task!\n");
94 for (int i=0;i<PEERS_REQUESTED;i++)
95 {
96 if (NULL != op[i])
97 {
98 GNUNET_TESTBED_operation_done(op[i]);
99 op[i] = NULL;
100 }
101 if (NULL != pi_op[i])
102 {
103 GNUNET_TESTBED_operation_done (pi_op[i]);
104 pi_op[i] = NULL;
105 }
106 }
107
108 if (NULL != multicast_peers)
109 {
110 for (int i=0; i < PEERS_REQUESTED; i++)
111 {
112 GNUNET_free_non_null (multicast_peers[i]->key);
113 GNUNET_free (multicast_peers[i]);
114 multicast_peers[i] = NULL;
115 }
116 GNUNET_free (multicast_peers);
117 multicast_peers = NULL;
118 }
119
120 if (NULL != timeout_tid)
121 {
122 GNUNET_SCHEDULER_cancel (timeout_tid);
123 timeout_tid = NULL;
124 }
125}
126
127
128static void
129timeout_task (void *cls)
130{
131 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
132 "Timeout!\n");
133 result = GNUNET_SYSERR;
134 GNUNET_SCHEDULER_shutdown ();
135}
136
137
138static void
139member_join_request (void *cls,
140 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
141 const struct GNUNET_MessageHeader *join_msg,
142 struct GNUNET_MULTICAST_JoinHandle *jh)
143{
144 struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls;
145 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
146 "Peer #%u (%s) sent a join request.\n",
147 mc_peer->peer,
148 GNUNET_i2s (multicast_peers[mc_peer->peer]->id));
149}
150
151
152static int
153notify (void *cls,
154 size_t *data_size,
155 void *data)
156{
157 struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls;
158
159 struct pingpong_msg *pp_msg = GNUNET_new (struct pingpong_msg);
160 pp_msg->peer = mc_peer->peer;
161 pp_msg->msg = PING;
162
163 *data_size = sizeof (struct pingpong_msg);
164 GNUNET_memcpy(data, pp_msg, *data_size);
165 GNUNET_free (pp_msg);
166
167 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
168 "Peer #%u sents ping to origin\n", mc_peer->peer);
169
170 return GNUNET_YES;
171}
172
173
174static void
175member_join_decision (void *cls,
176 int is_admitted,
177 const struct GNUNET_PeerIdentity *peer,
178 uint16_t relay_count,
179 const struct GNUNET_PeerIdentity *relays,
180 const struct GNUNET_MessageHeader *join_msg)
181{
182 struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls;
183
184 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
185 "Peer #%u (%s) received a decision from origin: %s\n",
186 mc_peer->peer,
187 GNUNET_i2s (multicast_peers[mc_peer->peer]->id),
188 (GNUNET_YES == is_admitted)?"accepted":"rejected");
189
190 if (GNUNET_YES == is_admitted)
191 {
192 GNUNET_MULTICAST_member_to_origin (members[mc_peer->peer],
193 0,
194 notify,
195 cls);
196
197 }
198}
199
200
201static void
202member_replay_frag ()
203{
204 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
205 "member replay frag...\n");
206}
207
208
209static void
210member_replay_msg ()
211{
212 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
213 "member replay msg...\n");
214}
215
216
217static void
218origin_disconnected_cb (void *cls)
219{
220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
221 "Origin disconnected. Shutting down.\n");
222 result = GNUNET_YES;
223 GNUNET_SCHEDULER_shutdown ();
224}
225
226
227static void
228member_disconnected_cb (void *cls)
229{
230 for (int i = 1; i < PEERS_REQUESTED; ++i)
231 if (GNUNET_NO == multicast_peers[i]->test_ok)
232 return;
233 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
234 "All member disconnected. Stopping origin.\n");
235 GNUNET_MULTICAST_origin_stop (origin, origin_disconnected_cb, cls);
236}
237
238
239static void
240member_message (void *cls,
241 const struct GNUNET_MULTICAST_MessageHeader *msg)
242{
243 struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls;
244 struct pingpong_msg *pp_msg = (struct pingpong_msg*) &(msg[1]);
245
246 if (PONG == pp_msg->msg && mc_peer->peer == pp_msg->peer)
247 {
248 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
249 "peer #%i (%s) receives a pong\n",
250 mc_peer->peer,
251 GNUNET_i2s (multicast_peers[mc_peer->peer]->id));
252 mc_peer->test_ok = GNUNET_OK;
253 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
254 "peer #%u (%s) parting from multicast group\n",
255 mc_peer->peer,
256 GNUNET_i2s (multicast_peers[mc_peer->peer]->id));
257
258 GNUNET_MULTICAST_member_part (members[mc_peer->peer], member_disconnected_cb, cls);
259 }
260}
261
262
263static void
264origin_join_request (void *cls,
265 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
266 const struct GNUNET_MessageHeader *join_msg,
267 struct GNUNET_MULTICAST_JoinHandle *jh)
268{
269 struct GNUNET_MessageHeader *join_resp;
270
271 uint8_t data_size = ntohs (join_msg->size);
272
273 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
274 "origin got a join request...\n");
275 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
276 "origin receives: '%s'\n", (char *)&join_msg[1]);
277
278 char data[] = "Come in!";
279 data_size = strlen (data) + 1;
280 join_resp = GNUNET_malloc (sizeof (join_resp) + data_size);
281 join_resp->size = htons (sizeof (join_resp) + data_size);
282 join_resp->type = htons (123);
283 GNUNET_memcpy (&join_resp[1], data, data_size);
284
285 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
286 "origin sends: '%s'\n", data);
287
288 GNUNET_MULTICAST_join_decision (jh,
289 GNUNET_YES,
290 0,
291 NULL,
292 join_resp);
293
294 result = GNUNET_OK;
295}
296
297
298static void
299origin_replay_frag (void *cls,
300 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
301 uint64_t fragment_id,
302 uint64_t flags,
303 struct GNUNET_MULTICAST_ReplayHandle *rh)
304{
305 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin replay fraq msg\n");
306}
307
308
309static void
310origin_replay_msg (void *cls,
311 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
312 uint64_t message_id,
313 uint64_t fragment_offset,
314 uint64_t flags,
315 struct GNUNET_MULTICAST_ReplayHandle *rh)
316{
317
318 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin replay msg\n");
319}
320
321
322static int
323origin_notify (void *cls,
324 size_t *data_size,
325 void *data)
326{
327 struct pingpong_msg *rcv_pp_msg = (struct pingpong_msg*)cls;
328 struct pingpong_msg *pp_msg = GNUNET_new (struct pingpong_msg);
329
330 pp_msg->peer = rcv_pp_msg->peer;
331 pp_msg->msg = PONG;
332 *data_size = sizeof (struct pingpong_msg);
333 GNUNET_memcpy(data, pp_msg, *data_size);
334 GNUNET_free (pp_msg);
335
336 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin sends pong\n");
337
338 return GNUNET_YES;
339}
340
341
342static void
343origin_request (void *cls,
344 const struct GNUNET_MULTICAST_RequestHeader *req)
345{
346 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin receives a msg\n");
347
348 req++;
349 struct pingpong_msg *pp_msg = (struct pingpong_msg *) req;
350
351 if (1 != pp_msg->msg) {
352 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "origin didn't reveice a correct request");
353 }
354
355 GNUNET_MULTICAST_origin_to_all (origin,
356 0,
357 0,
358 origin_notify,
359 pp_msg);
360}
361
362
363static void
364origin_message (void *cls,
365 const struct GNUNET_MULTICAST_MessageHeader *msg)
366{
367 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin message msg\n");
368}
369
370
371static void
372multicast_disconnect (void *cls,
373 void *op_result)
374{
375
376}
377
378
379static void *
380multicast_connect (void *cls,
381 const struct GNUNET_CONFIGURATION_Handle *cfg)
382{
383 struct MulticastPeerContext *multicast_peer = cls;
384 struct GNUNET_MessageHeader *join_msg;
385 char data[64];
386
387 if (0 == multicast_peer->peer)
388 {
389 group_key = GNUNET_CRYPTO_eddsa_key_create ();
390 GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key);
391
392 GNUNET_CRYPTO_hash (&group_pub_key, sizeof (group_pub_key), &group_pub_key_hash);
393 origin = GNUNET_MULTICAST_origin_start (cfg,
394 group_key,
395 0,
396 origin_join_request,
397 origin_replay_frag,
398 origin_replay_msg,
399 origin_request,
400 origin_message,
401 cls);
402 if (NULL == origin)
403 {
404 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
405 "Peer #%u could not create a multicast group",
406 multicast_peer->peer);
407 return NULL;
408 }
409 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
410 "Peer #%u connected as origin to group %s\n",
411 multicast_peer->peer,
412 GNUNET_h2s (&group_pub_key_hash));
413 return origin;
414 }
415 else
416 {
417 multicast_peer->key = GNUNET_CRYPTO_ecdsa_key_create ();
418
419 sprintf(data, "Hi, I am peer #%u (%s). Can I enter?",
420 multicast_peer->peer,
421 GNUNET_i2s (multicast_peers[multicast_peer->peer]->id));
422 uint8_t data_size = strlen (data) + 1;
423 join_msg = GNUNET_malloc (sizeof (join_msg) + data_size);
424 join_msg->size = htons (sizeof (join_msg) + data_size);
425 join_msg->type = htons (123);
426 GNUNET_memcpy (&join_msg[1], data, data_size);
427
428 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
429 "Peer #%u (%s) tries to join multicast group %s\n",
430 multicast_peer->peer,
431 GNUNET_i2s (multicast_peers[multicast_peer->peer]->id),
432 GNUNET_h2s (&group_pub_key_hash));
433
434 members[multicast_peer->peer] =
435 GNUNET_MULTICAST_member_join (cfg,
436 &group_pub_key,
437 multicast_peer->key,
438 multicast_peers[0]->id,
439 0,
440 NULL,
441 join_msg, /* join message */
442 member_join_request,
443 member_join_decision,
444 member_replay_frag,
445 member_replay_msg,
446 member_message,
447 cls);
448 return members[multicast_peer->peer];
449 }
450}
451
452
453static void
454peer_information_cb (void *cls,
455 struct GNUNET_TESTBED_Operation *operation,
456 const struct GNUNET_TESTBED_PeerInformation *pinfo,
457 const char *emsg)
458{
459 struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls;
460
461 if (NULL == pinfo) {
462 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "got no peer information\n");
463 result = GNUNET_SYSERR;
464 GNUNET_SCHEDULER_shutdown ();
465 }
466
467 multicast_peers[mc_peer->peer]->id = pinfo->result.id;
468
469 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
470 "Got peer information of %s (%s)\n",
471 (0 == mc_peer->peer)? "origin" : "member",
472 GNUNET_i2s (pinfo->result.id));
473
474 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
475 "Create peer #%u (%s)\n",
476 mc_peer->peer,
477 GNUNET_i2s (multicast_peers[mc_peer->peer]->id));
478
479 if (0 != mc_peer->peer)
480 {
481 /* connect to multicast service of members */
482 op[mc_peer->peer] =
483 GNUNET_TESTBED_service_connect (/* Closure for operation */
484 NULL,
485 /* The peer whose service to connect to */
486 peers[mc_peer->peer],
487 /* The name of the service */
488 "multicast",
489 /* called after a handle to service is opened */
490 service_connect,
491 /* closure for the above callback */
492 cls,
493 /* called when opening the service connection */
494 multicast_connect,
495 /* called when closing the service connection */
496 multicast_disconnect,
497 /* closure for the above two callbacks */
498 cls);
499 }
500}
501
502
503static void
504service_connect (void *cls,
505 struct GNUNET_TESTBED_Operation *op,
506 void *ca_result,
507 const char *emsg)
508{
509 struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls;
510
511 if (NULL == ca_result)
512 {
513 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
514 "Connection adapter not created for peer #%u (%s)\n",
515 mc_peer->peer,
516 GNUNET_i2s (multicast_peers[mc_peer->peer]->id));
517
518 result = GNUNET_SYSERR;
519 GNUNET_SCHEDULER_shutdown();
520 }
521
522 if (0 == mc_peer->peer)
523 {
524 // Get GNUnet identity of members
525 for (int i = 0; i<PEERS_REQUESTED; i++)
526 {
527 pi_op[i] = GNUNET_TESTBED_peer_get_information (peers[i],
528 GNUNET_TESTBED_PIT_IDENTITY,
529 peer_information_cb,
530 multicast_peers[i]);
531 }
532 }
533}
534
535
536
537/**
538 * Main function inovked from TESTBED once all of the
539 * peers are up and running. This one then connects
540 * just to the multicast service of peer 0 and 1.
541 * Peer 0 is going to be origin.
542 * Peer 1 is going to be one member.
543 * Origin will start a multicast group and the member will try to join it.
544 * After that we execute some multicast test.
545 *
546 * @param cls closure
547 * @param h the run handle
548 * @param peers started peers for the test
549 * @param PEERS_REQUESTED size of the 'peers' array
550 * @param links_succeeded number of links between peers that were created
551 * @param links_failed number of links testbed was unable to establish
552 */
553static void
554testbed_master (void *cls,
555 struct GNUNET_TESTBED_RunHandle *h,
556 unsigned int num_peers,
557 struct GNUNET_TESTBED_Peer **p,
558 unsigned int links_succeeded,
559 unsigned int links_failed)
560{
561 /* Testbed is ready with peers running and connected in a pre-defined overlay
562 topology (FIXME) */
563 peers = p;
564 multicast_peers = GNUNET_new_array (PEERS_REQUESTED, struct MulticastPeerContext*);
565
566 // Create test contexts for members
567 for (int i = 0; i<PEERS_REQUESTED; i++)
568 {
569 multicast_peers[i] = GNUNET_new (struct MulticastPeerContext);
570 multicast_peers[i]->peer = i;
571 multicast_peers[i]->test_ok = GNUNET_NO;
572 }
573 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
574 "Create origin peer\n");
575 op[0] =
576 GNUNET_TESTBED_service_connect (/* Closure for operation */
577 NULL,
578 /* The peer whose service to connect to */
579 peers[0],
580 /* The name of the service */
581 "multicast",
582 /* called after a handle to service is opened */
583 service_connect,
584 /* closure for the above callback */
585 multicast_peers[0],
586 /* called when opening the service connection */
587 multicast_connect,
588 /* called when closing the service connection */
589 multicast_disconnect,
590 /* closure for the above two callbacks */
591 multicast_peers[0]);
592 /* Schedule a new task on shutdown */
593 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
594 /* Schedule the shutdown task with a delay of a few Seconds */
595 timeout_tid =
596 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
597 (GNUNET_TIME_UNIT_SECONDS, 400),
598 &timeout_task,
599 NULL);
600}
601
602
603int
604main (int argc, char *argv[])
605{
606 int ret;
607 char const *config_file;
608
609 if (strstr (argv[0], "_line") != NULL)
610 {
611 config_file = "test_multicast_line.conf";
612 }
613 else if (strstr(argv[0], "_star") != NULL)
614 {
615 config_file = "test_multicast_star.conf";
616 }
617 else
618 {
619 config_file = "test_multicast_star.conf";
620 }
621
622 result = GNUNET_SYSERR;
623 ret =
624 GNUNET_TESTBED_test_run ("test-multicast-multipeer",
625 config_file,
626 /* number of peers to start */
627 PEERS_REQUESTED,
628 /* Event mask - set to 0 for no event notifications */
629 0LL,
630 /* Controller event callback */
631 NULL,
632 /* Closure for controller event callback */
633 NULL,
634 /* called when testbed setup is complete */
635 testbed_master,
636 /* Closure for the test_master callback */
637 NULL);
638 if ( (GNUNET_OK != ret) || (GNUNET_OK != result) )
639 return 1;
640 return 0;
641}
642
643/* 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 @@
1[testbed]
2HOSTNAME = localhost
3OVERLAY_TOPOLOGY = STAR
4
5[arm]
6GLOBAL_POSTFIX=-L ERROR
7
8[multicast]
9#PREFIX = tmux new-window gdb -x ./cmd.gdb --args
10#PREFIX = valgrind --leak-check=full
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock
12
13[vpn]
14START_ON_DEMAND = NO
15
16[peerinfo]
17# Do not use shipped gnunet HELLOs
18USE_INCLUDED_HELLOS = NO
19
20# Option to disable all disk IO; only useful for testbed runs
21# (large-scale experiments); disables persistence of HELLOs!
22NO_IO = YES
23
24[cadet]
25ID_ANNOUNCE_TIME = 5 s
26
27[hostlist]
28IMMEDIATE_START = NO
29START_ON_DEMAND = NO
30
31[nat]
32ENABLE_UPNP = NO
33
34[fs]
35IMMEDIATE_START = NO
36START_ON_DEMAND = NO
37
38[vpn]
39IMMEDIATE_START = NO
40START_ON_DEMAND = NO
41
42[revocation]
43IMMEDIATE_START = NO
44START_ON_DEMAND = NO
45
46[gns]
47IMMEDIATE_START = NO
48START_ON_DEMAND = NO
49
50[namestore]
51IMMEDIATE_START = NO
52START_ON_DEMAND = NO
53
54[namecache]
55IMMEDIATE_START = NO
56START_ON_DEMAND = NO
57
58[topology]
59IMMEDIATE_START = NO
60START_ON_DEMAND = NO
61
62[nse]
63WORKBITS = 0
64
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 @@
1gnunet-service-psyc
2test_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 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4pkgcfgdir= $(pkgdatadir)/config.d/
5
6libexecdir= $(pkglibdir)/libexec/
7
8pkgcfg_DATA = \
9 psyc.conf
10
11
12if MINGW
13 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
14endif
15
16if USE_COVERAGE
17 AM_CFLAGS = --coverage -O0
18 XLIB = -lgcov
19endif
20
21lib_LTLIBRARIES = libgnunetpsyc.la
22
23libgnunetpsyc_la_SOURCES = \
24 psyc_api.c psyc.h
25libgnunetpsyc_la_LIBADD = \
26 $(top_builddir)/src/util/libgnunetutil.la \
27 $(top_builddir)/src/psycutil/libgnunetpsycutil.la \
28 $(GN_LIBINTL) $(XLIB)
29libgnunetpsyc_la_LDFLAGS = \
30 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
31 -version-info 0:0:0
32
33bin_PROGRAMS =
34
35libexec_PROGRAMS = \
36 gnunet-service-psyc
37
38gnunet_service_psyc_SOURCES = \
39 gnunet-service-psyc.c
40gnunet_service_psyc_LDADD = \
41 $(top_builddir)/src/util/libgnunetutil.la \
42 $(top_builddir)/src/statistics/libgnunetstatistics.la \
43 $(top_builddir)/src/multicast/libgnunetmulticast.la \
44 $(top_builddir)/src/psycstore/libgnunetpsycstore.la \
45 $(top_builddir)/src/psycutil/libgnunetpsycutil.la \
46 $(GN_LIBINTL)
47gnunet_service_psyc_CFLAGS = $(AM_CFLAGS)
48
49
50if HAVE_TESTING
51check_PROGRAMS = \
52 test_psyc
53# test_psyc2
54endif
55
56if ENABLE_TEST_RUN
57AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
58TESTS = $(check_PROGRAMS)
59endif
60
61test_psyc_SOURCES = \
62 test_psyc.c
63test_psyc_LDADD = \
64 libgnunetpsyc.la \
65 $(top_builddir)/src/psycutil/libgnunetpsycutil.la \
66 $(top_builddir)/src/testing/libgnunettesting.la \
67 $(top_builddir)/src/util/libgnunetutil.la
68#test_psyc2_SOURCES = \
69# test_psyc2.c
70#test_psyc2_LDADD = \
71# libgnunetpsyc.la \
72# $(top_builddir)/src/psycutil/libgnunetpsycutil.la \
73# $(top_builddir)/src/testbed/libgnunettestbed.la \
74# $(top_builddir)/src/util/libgnunetutil.la
75
76EXTRA_DIST = \
77 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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file psyc/gnunet-service-psyc.c
23 * @brief PSYC service
24 * @author Gabor X Toth
25 */
26
27#include <inttypes.h>
28
29#include "platform.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_constants.h"
32#include "gnunet_protocols.h"
33#include "gnunet_statistics_service.h"
34#include "gnunet_multicast_service.h"
35#include "gnunet_psycstore_service.h"
36#include "gnunet_psyc_service.h"
37#include "gnunet_psyc_util_lib.h"
38#include "psyc.h"
39
40
41/**
42 * Handle to our current configuration.
43 */
44static const struct GNUNET_CONFIGURATION_Handle *cfg;
45
46/**
47 * Service handle.
48 */
49static struct GNUNET_SERVICE_Handle *service;
50
51/**
52 * Handle to the statistics service.
53 */
54static struct GNUNET_STATISTICS_Handle *stats;
55
56/**
57 * Handle to the PSYCstore.
58 */
59static struct GNUNET_PSYCSTORE_Handle *store;
60
61/**
62 * All connected masters.
63 * Channel's pub_key_hash -> struct Master
64 */
65static struct GNUNET_CONTAINER_MultiHashMap *masters;
66
67/**
68 * All connected slaves.
69 * Channel's pub_key_hash -> struct Slave
70 */
71static struct GNUNET_CONTAINER_MultiHashMap *slaves;
72
73/**
74 * Connected slaves per channel.
75 * Channel's pub_key_hash -> Slave's pub_key -> struct Slave
76 */
77static struct GNUNET_CONTAINER_MultiHashMap *channel_slaves;
78
79
80/**
81 * Message in the transmission queue.
82 */
83struct TransmitMessage
84{
85 struct TransmitMessage *prev;
86 struct TransmitMessage *next;
87
88 struct GNUNET_SERVICE_Client *client;
89
90 /**
91 * ID assigned to the message.
92 */
93 uint64_t id;
94
95 /**
96 * Size of message.
97 */
98 uint16_t size;
99
100 /**
101 * Type of first message part.
102 */
103 uint16_t first_ptype;
104
105 /**
106 * Type of last message part.
107 */
108 uint16_t last_ptype;
109
110 /* Followed by message */
111};
112
113
114/**
115 * Cache for received message fragments.
116 * Message fragments are only sent to clients after all modifiers arrived.
117 *
118 * chan_key -> MultiHashMap chan_msgs
119 */
120static struct GNUNET_CONTAINER_MultiHashMap *recv_cache;
121
122
123/**
124 * Entry in the chan_msgs hashmap of @a recv_cache:
125 * fragment_id -> RecvCacheEntry
126 */
127struct RecvCacheEntry
128{
129 struct GNUNET_MULTICAST_MessageHeader *mmsg;
130 uint16_t ref_count;
131};
132
133
134/**
135 * Entry in the @a recv_frags hash map of a @a Channel.
136 * message_id -> FragmentQueue
137 */
138struct FragmentQueue
139{
140 /**
141 * Fragment IDs stored in @a recv_cache.
142 */
143 struct GNUNET_CONTAINER_Heap *fragments;
144
145 /**
146 * Total size of received fragments.
147 */
148 uint64_t size;
149
150 /**
151 * Total size of received header fragments (METHOD & MODIFIERs)
152 */
153 uint64_t header_size;
154
155 /**
156 * The @a state_delta field from struct GNUNET_PSYC_MessageMethod.
157 */
158 uint64_t state_delta;
159
160 /**
161 * The @a flags field from struct GNUNET_PSYC_MessageMethod.
162 */
163 uint32_t flags;
164
165 /**
166 * Receive state of message.
167 *
168 * @see MessageFragmentState
169 */
170 uint8_t state;
171
172 /**
173 * Whether the state is already modified in PSYCstore.
174 */
175 uint8_t state_is_modified;
176
177 /**
178 * Is the message queued for delivery to the client?
179 * i.e. added to the recv_msgs queue
180 */
181 uint8_t is_queued;
182};
183
184
185/**
186 * List of connected clients.
187 */
188struct ClientList
189{
190 struct ClientList *prev;
191 struct ClientList *next;
192
193 struct GNUNET_SERVICE_Client *client;
194};
195
196
197struct Operation
198{
199 struct Operation *prev;
200 struct Operation *next;
201
202 struct GNUNET_SERVICE_Client *client;
203 struct Channel *channel;
204 uint64_t op_id;
205 uint32_t flags;
206};
207
208
209/**
210 * Common part of the client context for both a channel master and slave.
211 */
212struct Channel
213{
214 struct ClientList *clients_head;
215 struct ClientList *clients_tail;
216
217 struct Operation *op_head;
218 struct Operation *op_tail;
219
220 struct TransmitMessage *tmit_head;
221 struct TransmitMessage *tmit_tail;
222
223 /**
224 * Current PSYCstore operation.
225 */
226 struct GNUNET_PSYCSTORE_OperationHandle *store_op;
227
228 /**
229 * Received fragments not yet sent to the client.
230 * message_id -> FragmentQueue
231 */
232 struct GNUNET_CONTAINER_MultiHashMap *recv_frags;
233
234 /**
235 * Received message IDs not yet sent to the client.
236 */
237 struct GNUNET_CONTAINER_Heap *recv_msgs;
238
239 /**
240 * Public key of the channel.
241 */
242 struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
243
244 /**
245 * Hash of @a pub_key.
246 */
247 struct GNUNET_HashCode pub_key_hash;
248
249 /**
250 * Last message ID sent to the client.
251 * 0 if there is no such message.
252 */
253 uint64_t max_message_id;
254
255 /**
256 * ID of the last stateful message, where the state operations has been
257 * processed and saved to PSYCstore and which has been sent to the client.
258 * 0 if there is no such message.
259 */
260 uint64_t max_state_message_id;
261
262 /**
263 * Expected value size for the modifier being received from the PSYC service.
264 */
265 uint32_t tmit_mod_value_size_expected;
266
267 /**
268 * Actual value size for the modifier being received from the PSYC service.
269 */
270 uint32_t tmit_mod_value_size;
271
272 /**
273 * Is this channel ready to receive messages from client?
274 * #GNUNET_YES or #GNUNET_NO
275 */
276 uint8_t is_ready;
277
278 /**
279 * Is the client disconnected?
280 * #GNUNET_YES or #GNUNET_NO
281 */
282 uint8_t is_disconnecting;
283
284 /**
285 * Is this a channel master (#GNUNET_YES), or slave (#GNUNET_NO)?
286 */
287 uint8_t is_master;
288
289 union {
290 struct Master *master;
291 struct Slave *slave;
292 };
293};
294
295
296/**
297 * Client context for a channel master.
298 */
299struct Master
300{
301 /**
302 * Channel struct common for Master and Slave
303 */
304 struct Channel channel;
305
306 /**
307 * Private key of the channel.
308 */
309 struct GNUNET_CRYPTO_EddsaPrivateKey priv_key;
310
311 /**
312 * Handle for the multicast origin.
313 */
314 struct GNUNET_MULTICAST_Origin *origin;
315
316 /**
317 * Transmit handle for multicast.
318 */
319 struct GNUNET_MULTICAST_OriginTransmitHandle *tmit_handle;
320
321 /**
322 * Incoming join requests from multicast.
323 * member_pub_key -> struct GNUNET_MULTICAST_JoinHandle *
324 */
325 struct GNUNET_CONTAINER_MultiHashMap *join_reqs;
326
327 /**
328 * Last message ID transmitted to this channel.
329 *
330 * Incremented before sending a message, thus the message_id in messages sent
331 * starts from 1.
332 */
333 uint64_t max_message_id;
334
335 /**
336 * ID of the last message with state operations transmitted to the channel.
337 * 0 if there is no such message.
338 */
339 uint64_t max_state_message_id;
340
341 /**
342 * Maximum group generation transmitted to the channel.
343 */
344 uint64_t max_group_generation;
345
346 /**
347 * @see enum GNUNET_PSYC_Policy
348 */
349 enum GNUNET_PSYC_Policy policy;
350};
351
352
353/**
354 * Client context for a channel slave.
355 */
356struct Slave
357{
358 /**
359 * Channel struct common for Master and Slave
360 */
361 struct Channel channel;
362
363 /**
364 * Private key of the slave.
365 */
366 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
367
368 /**
369 * Public key of the slave.
370 */
371 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
372
373 /**
374 * Hash of @a pub_key.
375 */
376 struct GNUNET_HashCode pub_key_hash;
377
378 /**
379 * Handle for the multicast member.
380 */
381 struct GNUNET_MULTICAST_Member *member;
382
383 /**
384 * Transmit handle for multicast.
385 */
386 struct GNUNET_MULTICAST_MemberTransmitHandle *tmit_handle;
387
388 /**
389 * Peer identity of the origin.
390 */
391 struct GNUNET_PeerIdentity origin;
392
393 /**
394 * Number of items in @a relays.
395 */
396 uint32_t relay_count;
397
398 /**
399 * Relays that multicast can use to connect.
400 */
401 struct GNUNET_PeerIdentity *relays;
402
403 /**
404 * Join request to be transmitted to the master on join.
405 */
406 struct GNUNET_PSYC_Message *join_msg;
407
408 /**
409 * Join decision received from multicast.
410 */
411 struct GNUNET_PSYC_JoinDecisionMessage *join_dcsn;
412
413 /**
414 * Maximum request ID for this channel.
415 */
416 uint64_t max_request_id;
417
418 /**
419 * Join flags.
420 */
421 enum GNUNET_PSYC_SlaveJoinFlags join_flags;
422};
423
424
425/**
426 * Client context.
427 */
428struct Client {
429 struct GNUNET_SERVICE_Client *client;
430 struct Channel *channel;
431};
432
433
434struct ReplayRequestKey
435{
436 uint64_t fragment_id;
437 uint64_t message_id;
438 uint64_t fragment_offset;
439 uint64_t flags;
440};
441
442
443static void
444transmit_message (struct Channel *chn);
445
446static uint64_t
447message_queue_run (struct Channel *chn);
448
449static uint64_t
450message_queue_drop (struct Channel *chn);
451
452
453static void
454schedule_transmit_message (void *cls)
455{
456 struct Channel *chn = cls;
457
458 transmit_message (chn);
459}
460
461
462/**
463 * Task run during shutdown.
464 *
465 * @param cls unused
466 */
467static void
468shutdown_task (void *cls)
469{
470 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
471 "shutting down...\n");
472 GNUNET_PSYCSTORE_disconnect (store);
473 if (NULL != stats)
474 {
475 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
476 stats = NULL;
477 }
478}
479
480
481static struct Operation *
482op_add (struct Channel *chn, struct GNUNET_SERVICE_Client *client,
483 uint64_t op_id, uint32_t flags)
484{
485 struct Operation *op = GNUNET_malloc (sizeof (*op));
486 op->client = client;
487 op->channel = chn;
488 op->op_id = op_id;
489 op->flags = flags;
490 GNUNET_CONTAINER_DLL_insert (chn->op_head, chn->op_tail, op);
491 return op;
492}
493
494
495static void
496op_remove (struct Operation *op)
497{
498 GNUNET_CONTAINER_DLL_remove (op->channel->op_head, op->channel->op_tail, op);
499 GNUNET_free (op);
500}
501
502
503/**
504 * Clean up master data structures after a client disconnected.
505 */
506static void
507cleanup_master (struct Master *mst)
508{
509 struct Channel *chn = &mst->channel;
510
511 GNUNET_CONTAINER_multihashmap_destroy (mst->join_reqs);
512 GNUNET_CONTAINER_multihashmap_remove (masters, &chn->pub_key_hash, mst);
513}
514
515
516/**
517 * Clean up slave data structures after a client disconnected.
518 */
519static void
520cleanup_slave (struct Slave *slv)
521{
522 struct Channel *chn = &slv->channel;
523 struct GNUNET_CONTAINER_MultiHashMap *
524 chn_slv = GNUNET_CONTAINER_multihashmap_get (channel_slaves,
525 &chn->pub_key_hash);
526 GNUNET_assert (NULL != chn_slv);
527 GNUNET_CONTAINER_multihashmap_remove (chn_slv, &slv->pub_key_hash, slv);
528
529 if (0 == GNUNET_CONTAINER_multihashmap_size (chn_slv))
530 {
531 GNUNET_CONTAINER_multihashmap_remove (channel_slaves, &chn->pub_key_hash,
532 chn_slv);
533 GNUNET_CONTAINER_multihashmap_destroy (chn_slv);
534 }
535 GNUNET_CONTAINER_multihashmap_remove (slaves, &chn->pub_key_hash, slv);
536
537 if (NULL != slv->join_msg)
538 {
539 GNUNET_free (slv->join_msg);
540 slv->join_msg = NULL;
541 }
542 if (NULL != slv->relays)
543 {
544 GNUNET_free (slv->relays);
545 slv->relays = NULL;
546 }
547 GNUNET_CONTAINER_multihashmap_remove (slaves, &chn->pub_key_hash, slv);
548}
549
550
551/**
552 * Clean up channel data structures after a client disconnected.
553 */
554static void
555cleanup_channel (struct Channel *chn)
556{
557 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
558 "%p Cleaning up channel %s. master? %u\n",
559 chn,
560 GNUNET_h2s (&chn->pub_key_hash),
561 chn->is_master);
562 message_queue_drop (chn);
563 GNUNET_CONTAINER_multihashmap_destroy (chn->recv_frags);
564 chn->recv_frags = NULL;
565
566 if (NULL != chn->store_op)
567 {
568 GNUNET_PSYCSTORE_operation_cancel (chn->store_op);
569 chn->store_op = NULL;
570 }
571
572 (GNUNET_YES == chn->is_master)
573 ? cleanup_master (chn->master)
574 : cleanup_slave (chn->slave);
575 GNUNET_free (chn);
576}
577
578
579/**
580 * Called whenever a client is disconnected.
581 * Frees our resources associated with that client.
582 *
583 * @param cls closure
584 * @param client identification of the client
585 * @param app_ctx must match @a client
586 */
587static void
588client_notify_disconnect (void *cls,
589 struct GNUNET_SERVICE_Client *client,
590 void *app_ctx)
591{
592 struct Client *c = app_ctx;
593 struct Channel *chn = c->channel;
594 GNUNET_free (c);
595
596 if (NULL == chn)
597 {
598 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
599 "%p User context is NULL in client_notify_disconnect ()\n",
600 chn);
601 GNUNET_break (0);
602 return;
603 }
604
605 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
606 "%p Client %p (%s) disconnected from channel %s\n",
607 chn,
608 client,
609 (GNUNET_YES == chn->is_master) ? "master" : "slave",
610 GNUNET_h2s (&chn->pub_key_hash));
611
612 struct ClientList *cli = chn->clients_head;
613 while (NULL != cli)
614 {
615 if (cli->client == client)
616 {
617 GNUNET_CONTAINER_DLL_remove (chn->clients_head, chn->clients_tail, cli);
618 GNUNET_free (cli);
619 break;
620 }
621 cli = cli->next;
622 }
623
624 struct Operation *op = chn->op_head;
625 while (NULL != op)
626 {
627 if (op->client == client)
628 {
629 op->client = NULL;
630 break;
631 }
632 op = op->next;
633 }
634
635 if (NULL == chn->clients_head)
636 { /* Last client disconnected. */
637 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
638 "%p Last client (%s) disconnected from channel %s\n",
639 chn,
640 (GNUNET_YES == chn->is_master) ? "master" : "slave",
641 GNUNET_h2s (&chn->pub_key_hash));
642 chn->is_disconnecting = GNUNET_YES;
643 cleanup_channel (chn);
644 }
645}
646
647
648/**
649 * A new client connected.
650 *
651 * @param cls NULL
652 * @param client client to add
653 * @param mq message queue for @a client
654 * @return @a client
655 */
656static void *
657client_notify_connect (void *cls,
658 struct GNUNET_SERVICE_Client *client,
659 struct GNUNET_MQ_Handle *mq)
660{
661 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client connected: %p\n", client);
662
663 struct Client *c = GNUNET_malloc (sizeof (*c));
664 c->client = client;
665
666 return c;
667}
668
669
670/**
671 * Send message to all clients connected to the channel.
672 */
673static void
674client_send_msg (const struct Channel *chn,
675 const struct GNUNET_MessageHeader *msg)
676{
677 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
678 "Sending message to clients of channel %p.\n",
679 chn);
680
681 struct ClientList *cli = chn->clients_head;
682 while (NULL != cli)
683 {
684 struct GNUNET_MQ_Envelope *
685 env = GNUNET_MQ_msg_copy (msg);
686
687 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (cli->client),
688 env);
689 cli = cli->next;
690 }
691}
692
693
694/**
695 * Send a result code back to the client.
696 *
697 * @param client
698 * Client that should receive the result code.
699 * @param result_code
700 * Code to transmit.
701 * @param op_id
702 * Operation ID in network byte order.
703 * @param data
704 * Data payload or NULL.
705 * @param data_size
706 * Size of @a data.
707 */
708static void
709client_send_result (struct GNUNET_SERVICE_Client *client, uint64_t op_id,
710 int64_t result_code, const void *data, uint16_t data_size)
711{
712 struct GNUNET_OperationResultMessage *res;
713 struct GNUNET_MQ_Envelope *
714 env = GNUNET_MQ_msg_extra (res,
715 data_size,
716 GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE);
717 res->result_code = GNUNET_htonll (result_code);
718 res->op_id = op_id;
719 if (0 < data_size)
720 GNUNET_memcpy (&res[1], data, data_size);
721
722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
723 "%p Sending result to client for OP ID %" PRIu64 ": %" PRId64 " (size: %u)\n",
724 client,
725 GNUNET_ntohll (op_id),
726 result_code,
727 data_size);
728
729 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
730}
731
732
733/**
734 * Closure for join_mem_test_cb()
735 */
736struct JoinMemTestClosure
737{
738 struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key;
739 struct Channel *channel;
740 struct GNUNET_MULTICAST_JoinHandle *join_handle;
741 struct GNUNET_PSYC_JoinRequestMessage *join_msg;
742};
743
744
745/**
746 * Membership test result callback used for join requests.
747 */
748static void
749join_mem_test_cb (void *cls, int64_t result,
750 const char *err_msg, uint16_t err_msg_size)
751{
752 struct JoinMemTestClosure *jcls = cls;
753
754 if (GNUNET_NO == result && GNUNET_YES == jcls->channel->is_master)
755 { /* Pass on join request to client if this is a master channel */
756 struct Master *mst = jcls->channel->master;
757 struct GNUNET_HashCode slave_pub_hash;
758 GNUNET_CRYPTO_hash (&jcls->slave_pub_key, sizeof (jcls->slave_pub_key),
759 &slave_pub_hash);
760 GNUNET_CONTAINER_multihashmap_put (mst->join_reqs, &slave_pub_hash, jcls->join_handle,
761 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
762 client_send_msg (jcls->channel, &jcls->join_msg->header);
763 }
764 else
765 {
766 if (GNUNET_SYSERR == result)
767 {
768 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
769 "Could not perform membership test (%.*s)\n",
770 err_msg_size, err_msg);
771 }
772 // FIXME: add relays
773 GNUNET_MULTICAST_join_decision (jcls->join_handle, result, 0, NULL, NULL);
774 }
775 GNUNET_free (jcls->join_msg);
776 GNUNET_free (jcls);
777}
778
779
780/**
781 * Incoming join request from multicast.
782 */
783static void
784mcast_recv_join_request (void *cls,
785 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key,
786 const struct GNUNET_MessageHeader *join_msg,
787 struct GNUNET_MULTICAST_JoinHandle *jh)
788{
789 struct Channel *chn = cls;
790 uint16_t join_msg_size = 0;
791
792 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
793 "%p Got join request.\n",
794 chn);
795 if (NULL != join_msg)
796 {
797 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE == ntohs (join_msg->type))
798 {
799 join_msg_size = ntohs (join_msg->size);
800 }
801 else
802 {
803 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
804 "%p Got join message with invalid type %u.\n",
805 chn,
806 ntohs (join_msg->type));
807 }
808 }
809
810 struct GNUNET_PSYC_JoinRequestMessage *
811 req = GNUNET_malloc (sizeof (*req) + join_msg_size);
812 req->header.size = htons (sizeof (*req) + join_msg_size);
813 req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST);
814 req->slave_pub_key = *slave_pub_key;
815 if (0 < join_msg_size)
816 GNUNET_memcpy (&req[1], join_msg, join_msg_size);
817
818 struct JoinMemTestClosure *jcls = GNUNET_malloc (sizeof (*jcls));
819 jcls->slave_pub_key = *slave_pub_key;
820 jcls->channel = chn;
821 jcls->join_handle = jh;
822 jcls->join_msg = req;
823
824 GNUNET_PSYCSTORE_membership_test (store, &chn->pub_key, slave_pub_key,
825 chn->max_message_id, 0,
826 &join_mem_test_cb, jcls);
827}
828
829
830/**
831 * Join decision received from multicast.
832 */
833static void
834mcast_recv_join_decision (void *cls, int is_admitted,
835 const struct GNUNET_PeerIdentity *peer,
836 uint16_t relay_count,
837 const struct GNUNET_PeerIdentity *relays,
838 const struct GNUNET_MessageHeader *join_resp)
839{
840 struct Slave *slv = cls;
841 struct Channel *chn = &slv->channel;
842 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
843 "%p Got join decision: %d\n",
844 slv,
845 is_admitted);
846 if (GNUNET_YES == chn->is_ready)
847 {
848 /* Already admitted */
849 return;
850 }
851
852 uint16_t join_resp_size = (NULL != join_resp) ? ntohs (join_resp->size) : 0;
853 struct GNUNET_PSYC_JoinDecisionMessage *
854 dcsn = slv->join_dcsn = GNUNET_malloc (sizeof (*dcsn) + join_resp_size);
855 dcsn->header.size = htons (sizeof (*dcsn) + join_resp_size);
856 dcsn->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION);
857 dcsn->is_admitted = htonl (is_admitted);
858 if (0 < join_resp_size)
859 GNUNET_memcpy (&dcsn[1], join_resp, join_resp_size);
860
861 client_send_msg (chn, &dcsn->header);
862
863 if (GNUNET_YES == is_admitted
864 && ! (GNUNET_PSYC_SLAVE_JOIN_LOCAL & slv->join_flags))
865 {
866 chn->is_ready = GNUNET_YES;
867 }
868}
869
870
871static int
872store_recv_fragment_replay (void *cls,
873 struct GNUNET_MULTICAST_MessageHeader *msg,
874 enum GNUNET_PSYCSTORE_MessageFlags flags)
875{
876 struct GNUNET_MULTICAST_ReplayHandle *rh = cls;
877
878 GNUNET_MULTICAST_replay_response (rh, &msg->header, GNUNET_MULTICAST_REC_OK);
879 return GNUNET_YES;
880}
881
882
883/**
884 * Received result of GNUNET_PSYCSTORE_fragment_get() for multicast replay.
885 */
886static void
887store_recv_fragment_replay_result (void *cls,
888 int64_t result,
889 const char *err_msg,
890 uint16_t err_msg_size)
891{
892 struct GNUNET_MULTICAST_ReplayHandle *rh = cls;
893
894 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
895 "%p Fragment replay: PSYCSTORE returned %" PRId64 " (%.*s)\n",
896 rh,
897 result,
898 err_msg_size,
899 err_msg);
900 switch (result)
901 {
902 case GNUNET_YES:
903 break;
904
905 case GNUNET_NO:
906 GNUNET_MULTICAST_replay_response (rh, NULL,
907 GNUNET_MULTICAST_REC_NOT_FOUND);
908 return;
909
910 case GNUNET_PSYCSTORE_MEMBERSHIP_TEST_FAILED:
911 GNUNET_MULTICAST_replay_response (rh, NULL,
912 GNUNET_MULTICAST_REC_ACCESS_DENIED);
913 return;
914
915 case GNUNET_SYSERR:
916 GNUNET_MULTICAST_replay_response (rh, NULL,
917 GNUNET_MULTICAST_REC_INTERNAL_ERROR);
918 return;
919 }
920 /* GNUNET_MULTICAST_replay_response frees 'rh' when passed
921 * an error code, so it must be ensured no further processing
922 * is attempted on 'rh'. Maybe this should be refactored as
923 * it doesn't look very intuitive. --lynX
924 */
925 GNUNET_MULTICAST_replay_response_end (rh);
926}
927
928
929/**
930 * Incoming fragment replay request from multicast.
931 */
932static void
933mcast_recv_replay_fragment (void *cls,
934 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key,
935 uint64_t fragment_id, uint64_t flags,
936 struct GNUNET_MULTICAST_ReplayHandle *rh)
937
938{
939 struct Channel *chn = cls;
940 GNUNET_PSYCSTORE_fragment_get (store, &chn->pub_key, slave_pub_key,
941 fragment_id, fragment_id,
942 &store_recv_fragment_replay,
943 &store_recv_fragment_replay_result, rh);
944}
945
946
947/**
948 * Incoming message replay request from multicast.
949 */
950static void
951mcast_recv_replay_message (void *cls,
952 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key,
953 uint64_t message_id,
954 uint64_t fragment_offset,
955 uint64_t flags,
956 struct GNUNET_MULTICAST_ReplayHandle *rh)
957{
958 struct Channel *chn = cls;
959 GNUNET_PSYCSTORE_message_get (store, &chn->pub_key, slave_pub_key,
960 message_id, message_id, 1, NULL,
961 &store_recv_fragment_replay,
962 &store_recv_fragment_replay_result, rh);
963}
964
965
966/**
967 * Convert an uint64_t in network byte order to a HashCode
968 * that can be used as key in a MultiHashMap
969 */
970static inline void
971hash_key_from_nll (struct GNUNET_HashCode *key, uint64_t n)
972{
973 /* use little-endian order, as idx_of MultiHashMap casts key to unsigned int */
974 /* TODO: use built-in byte swap functions if available */
975
976 n = ((n << 8) & 0xFF00FF00FF00FF00ULL) | ((n >> 8) & 0x00FF00FF00FF00FFULL);
977 n = ((n << 16) & 0xFFFF0000FFFF0000ULL) | ((n >> 16) & 0x0000FFFF0000FFFFULL);
978
979 *key = (struct GNUNET_HashCode) {};
980 *((uint64_t *) key)
981 = (n << 32) | (n >> 32);
982}
983
984
985/**
986 * Convert an uint64_t in host byte order to a HashCode
987 * that can be used as key in a MultiHashMap
988 */
989static inline void
990hash_key_from_hll (struct GNUNET_HashCode *key, uint64_t n)
991{
992#if __BYTE_ORDER == __BIG_ENDIAN
993 hash_key_from_nll (key, n);
994#elif __BYTE_ORDER == __LITTLE_ENDIAN
995 *key = (struct GNUNET_HashCode) {};
996 *((uint64_t *) key) = n;
997#else
998 #error byteorder undefined
999#endif
1000}
1001
1002
1003/**
1004 * Initialize PSYC message header.
1005 */
1006static inline void
1007psyc_msg_init (struct GNUNET_PSYC_MessageHeader *pmsg,
1008 const struct GNUNET_MULTICAST_MessageHeader *mmsg, uint32_t flags)
1009{
1010 uint16_t size = ntohs (mmsg->header.size);
1011 uint16_t psize = sizeof (*pmsg) + size - sizeof (*mmsg);
1012
1013 pmsg->header.size = htons (psize);
1014 pmsg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE);
1015 pmsg->message_id = mmsg->message_id;
1016 pmsg->fragment_offset = mmsg->fragment_offset;
1017 pmsg->flags = htonl (flags);
1018
1019 GNUNET_memcpy (&pmsg[1], &mmsg[1], size - sizeof (*mmsg));
1020}
1021
1022
1023/**
1024 * Create a new PSYC message from a multicast message for sending it to clients.
1025 */
1026static inline struct GNUNET_PSYC_MessageHeader *
1027psyc_msg_new (const struct GNUNET_MULTICAST_MessageHeader *mmsg, uint32_t flags)
1028{
1029 struct GNUNET_PSYC_MessageHeader *pmsg;
1030 uint16_t size = ntohs (mmsg->header.size);
1031 uint16_t psize = sizeof (*pmsg) + size - sizeof (*mmsg);
1032
1033 pmsg = GNUNET_malloc (psize);
1034 psyc_msg_init (pmsg, mmsg, flags);
1035 return pmsg;
1036}
1037
1038
1039/**
1040 * Send multicast message to all clients connected to the channel.
1041 */
1042static void
1043client_send_mcast_msg (struct Channel *chn,
1044 const struct GNUNET_MULTICAST_MessageHeader *mmsg,
1045 uint32_t flags)
1046{
1047 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1048 "%p Sending multicast message to client. fragment_id: %" PRIu64 ", message_id: %" PRIu64 "\n",
1049 chn,
1050 GNUNET_ntohll (mmsg->fragment_id),
1051 GNUNET_ntohll (mmsg->message_id));
1052
1053 struct GNUNET_PSYC_MessageHeader *
1054 pmsg = GNUNET_PSYC_message_header_create (mmsg, flags);
1055 client_send_msg (chn, &pmsg->header);
1056 GNUNET_free (pmsg);
1057}
1058
1059
1060/**
1061 * Send multicast request to all clients connected to the channel.
1062 */
1063static void
1064client_send_mcast_req (struct Master *mst,
1065 const struct GNUNET_MULTICAST_RequestHeader *req)
1066{
1067 struct Channel *chn = &mst->channel;
1068
1069 struct GNUNET_PSYC_MessageHeader *pmsg;
1070 uint16_t size = ntohs (req->header.size);
1071 uint16_t psize = sizeof (*pmsg) + size - sizeof (*req);
1072
1073 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1074 "%p Sending multicast request to client. fragment_id: %" PRIu64 ", message_id: %" PRIu64 "\n",
1075 chn,
1076 GNUNET_ntohll (req->fragment_id),
1077 GNUNET_ntohll (req->request_id));
1078
1079 pmsg = GNUNET_malloc (psize);
1080 pmsg->header.size = htons (psize);
1081 pmsg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE);
1082 pmsg->message_id = req->request_id;
1083 pmsg->fragment_offset = req->fragment_offset;
1084 pmsg->flags = htonl (GNUNET_PSYC_MESSAGE_REQUEST);
1085 pmsg->slave_pub_key = req->member_pub_key;
1086 GNUNET_memcpy (&pmsg[1], &req[1], size - sizeof (*req));
1087
1088 client_send_msg (chn, &pmsg->header);
1089
1090 /* FIXME: save req to PSYCstore so that it can be resent later to clients */
1091
1092 GNUNET_free (pmsg);
1093}
1094
1095
1096/**
1097 * Insert a multicast message fragment into the queue belonging to the message.
1098 *
1099 * @param chn Channel.
1100 * @param mmsg Multicast message fragment.
1101 * @param msg_id_hash Message ID of @a mmsg in a struct GNUNET_HashCode.
1102 * @param first_ptype First PSYC message part type in @a mmsg.
1103 * @param last_ptype Last PSYC message part type in @a mmsg.
1104 */
1105static void
1106fragment_queue_insert (struct Channel *chn,
1107 const struct GNUNET_MULTICAST_MessageHeader *mmsg,
1108 uint16_t first_ptype, uint16_t last_ptype)
1109{
1110 const uint16_t size = ntohs (mmsg->header.size);
1111 const uint64_t frag_offset = GNUNET_ntohll (mmsg->fragment_offset);
1112 struct GNUNET_CONTAINER_MultiHashMap
1113 *chan_msgs = GNUNET_CONTAINER_multihashmap_get (recv_cache,
1114 &chn->pub_key_hash);
1115
1116 struct GNUNET_HashCode msg_id_hash;
1117 hash_key_from_nll (&msg_id_hash, mmsg->message_id);
1118
1119 struct FragmentQueue
1120 *fragq = GNUNET_CONTAINER_multihashmap_get (chn->recv_frags, &msg_id_hash);
1121
1122 if (NULL == fragq)
1123 {
1124 fragq = GNUNET_malloc (sizeof (*fragq));
1125 fragq->state = MSG_FRAG_STATE_HEADER;
1126 fragq->fragments
1127 = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1128
1129 GNUNET_CONTAINER_multihashmap_put (chn->recv_frags, &msg_id_hash, fragq,
1130 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1131
1132 if (NULL == chan_msgs)
1133 {
1134 chan_msgs = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1135 GNUNET_CONTAINER_multihashmap_put (recv_cache, &chn->pub_key_hash, chan_msgs,
1136 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1137 }
1138 }
1139
1140 struct GNUNET_HashCode frag_id_hash;
1141 hash_key_from_nll (&frag_id_hash, mmsg->fragment_id);
1142 struct RecvCacheEntry
1143 *cache_entry = GNUNET_CONTAINER_multihashmap_get (chan_msgs, &frag_id_hash);
1144 if (NULL == cache_entry)
1145 {
1146 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1147 "%p Adding message fragment to cache. message_id: %" PRIu64 ", fragment_id: %" PRIu64 "\n",
1148 chn,
1149 GNUNET_ntohll (mmsg->message_id),
1150 GNUNET_ntohll (mmsg->fragment_id));
1151 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1152 "%p header_size: %" PRIu64 " + %u\n",
1153 chn,
1154 fragq->header_size,
1155 size);
1156 cache_entry = GNUNET_malloc (sizeof (*cache_entry));
1157 cache_entry->ref_count = 1;
1158 cache_entry->mmsg = GNUNET_malloc (size);
1159 GNUNET_memcpy (cache_entry->mmsg, mmsg, size);
1160 GNUNET_CONTAINER_multihashmap_put (chan_msgs, &frag_id_hash, cache_entry,
1161 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1162 }
1163 else
1164 {
1165 cache_entry->ref_count++;
1166 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1167 "%p Message fragment is already in cache. message_id: %" PRIu64 ", fragment_id: %" PRIu64 ", ref_count: %u\n",
1168 chn,
1169 GNUNET_ntohll (mmsg->message_id),
1170 GNUNET_ntohll (mmsg->fragment_id),
1171 cache_entry->ref_count);
1172 }
1173
1174 if (MSG_FRAG_STATE_HEADER == fragq->state)
1175 {
1176 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == first_ptype)
1177 {
1178 struct GNUNET_PSYC_MessageMethod *
1179 pmeth = (struct GNUNET_PSYC_MessageMethod *) &mmsg[1];
1180 fragq->state_delta = GNUNET_ntohll (pmeth->state_delta);
1181 fragq->flags = ntohl (pmeth->flags);
1182 }
1183
1184 if (last_ptype < GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA)
1185 {
1186 fragq->header_size += size;
1187 }
1188 else if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == first_ptype
1189 || frag_offset == fragq->header_size)
1190 { /* header is now complete */
1191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1192 "%p Header of message %" PRIu64 " is complete.\n",
1193 chn,
1194 GNUNET_ntohll (mmsg->message_id));
1195
1196 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1197 "%p Adding message %" PRIu64 " to queue.\n",
1198 chn,
1199 GNUNET_ntohll (mmsg->message_id));
1200 fragq->state = MSG_FRAG_STATE_DATA;
1201 }
1202 else
1203 {
1204 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1205 "%p Header of message %" PRIu64 " is NOT complete yet: %" PRIu64 " != %" PRIu64 "\n",
1206 chn,
1207 GNUNET_ntohll (mmsg->message_id),
1208 frag_offset,
1209 fragq->header_size);
1210 }
1211 }
1212
1213 switch (last_ptype)
1214 {
1215 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1216 if (frag_offset == fragq->size)
1217 fragq->state = MSG_FRAG_STATE_END;
1218 else
1219 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1220 "%p Message %" PRIu64 " is NOT complete yet: %" PRIu64 " != %" PRIu64 "\n",
1221 chn,
1222 GNUNET_ntohll (mmsg->message_id),
1223 frag_offset,
1224 fragq->size);
1225 break;
1226
1227 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
1228 /* Drop message without delivering to client if it's a single fragment */
1229 fragq->state =
1230 (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == first_ptype)
1231 ? MSG_FRAG_STATE_DROP
1232 : MSG_FRAG_STATE_CANCEL;
1233 }
1234
1235 switch (fragq->state)
1236 {
1237 case MSG_FRAG_STATE_DATA:
1238 case MSG_FRAG_STATE_END:
1239 case MSG_FRAG_STATE_CANCEL:
1240 if (GNUNET_NO == fragq->is_queued)
1241 {
1242 GNUNET_CONTAINER_heap_insert (chn->recv_msgs, NULL,
1243 GNUNET_ntohll (mmsg->message_id));
1244 fragq->is_queued = GNUNET_YES;
1245 }
1246 }
1247
1248 fragq->size += size;
1249 GNUNET_CONTAINER_heap_insert (fragq->fragments, NULL,
1250 GNUNET_ntohll (mmsg->fragment_id));
1251}
1252
1253
1254/**
1255 * Run fragment queue of a message.
1256 *
1257 * Send fragments of a message in order to client, after all modifiers arrived
1258 * from multicast.
1259 *
1260 * @param chn
1261 * Channel.
1262 * @param msg_id
1263 * ID of the message @a fragq belongs to.
1264 * @param fragq
1265 * Fragment queue of the message.
1266 * @param drop
1267 * Drop message without delivering to client?
1268 * #GNUNET_YES or #GNUNET_NO.
1269 */
1270static void
1271fragment_queue_run (struct Channel *chn, uint64_t msg_id,
1272 struct FragmentQueue *fragq, uint8_t drop)
1273{
1274 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1275 "%p Running message fragment queue for message %" PRIu64 " (state: %u).\n",
1276 chn,
1277 msg_id,
1278 fragq->state);
1279
1280 struct GNUNET_CONTAINER_MultiHashMap
1281 *chan_msgs = GNUNET_CONTAINER_multihashmap_get (recv_cache,
1282 &chn->pub_key_hash);
1283 GNUNET_assert (NULL != chan_msgs);
1284 uint64_t frag_id;
1285
1286 while (GNUNET_YES == GNUNET_CONTAINER_heap_peek2 (fragq->fragments, NULL,
1287 &frag_id))
1288 {
1289 struct GNUNET_HashCode frag_id_hash;
1290 hash_key_from_hll (&frag_id_hash, frag_id);
1291 struct RecvCacheEntry *cache_entry
1292 = GNUNET_CONTAINER_multihashmap_get (chan_msgs, &frag_id_hash);
1293 if (cache_entry != NULL)
1294 {
1295 if (GNUNET_NO == drop)
1296 {
1297 client_send_mcast_msg (chn, cache_entry->mmsg, 0);
1298 }
1299 if (cache_entry->ref_count <= 1)
1300 {
1301 GNUNET_CONTAINER_multihashmap_remove (chan_msgs, &frag_id_hash,
1302 cache_entry);
1303 GNUNET_free (cache_entry->mmsg);
1304 GNUNET_free (cache_entry);
1305 }
1306 else
1307 {
1308 cache_entry->ref_count--;
1309 }
1310 }
1311#if CACHE_AGING_IMPLEMENTED
1312 else if (GNUNET_NO == drop)
1313 {
1314 /* TODO: fragment not in cache anymore, retrieve it from PSYCstore */
1315 }
1316#endif
1317
1318 GNUNET_CONTAINER_heap_remove_root (fragq->fragments);
1319 }
1320
1321 if (MSG_FRAG_STATE_END <= fragq->state)
1322 {
1323 struct GNUNET_HashCode msg_id_hash;
1324 hash_key_from_hll (&msg_id_hash, msg_id);
1325
1326 GNUNET_CONTAINER_multihashmap_remove (chn->recv_frags, &msg_id_hash, fragq);
1327 GNUNET_CONTAINER_heap_destroy (fragq->fragments);
1328 GNUNET_free (fragq);
1329 }
1330 else
1331 {
1332 fragq->is_queued = GNUNET_NO;
1333 }
1334}
1335
1336
1337struct StateModifyClosure
1338{
1339 struct Channel *channel;
1340 uint64_t msg_id;
1341 struct GNUNET_HashCode msg_id_hash;
1342};
1343
1344
1345void
1346store_recv_state_modify_result (void *cls, int64_t result,
1347 const char *err_msg, uint16_t err_msg_size)
1348{
1349 struct StateModifyClosure *mcls = cls;
1350 struct Channel *chn = mcls->channel;
1351 uint64_t msg_id = mcls->msg_id;
1352
1353 struct FragmentQueue *
1354 fragq = GNUNET_CONTAINER_multihashmap_get (chn->recv_frags, &mcls->msg_id_hash);
1355
1356 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1357 "%p GNUNET_PSYCSTORE_state_modify() returned %" PRId64 " (%.*s)\n",
1358 chn, result, err_msg_size, err_msg);
1359
1360 switch (result)
1361 {
1362 case GNUNET_OK:
1363 case GNUNET_NO:
1364 if (NULL != fragq)
1365 fragq->state_is_modified = GNUNET_YES;
1366 if (chn->max_state_message_id < msg_id)
1367 chn->max_state_message_id = msg_id;
1368 if (chn->max_message_id < msg_id)
1369 chn->max_message_id = msg_id;
1370
1371 if (NULL != fragq)
1372 fragment_queue_run (chn, msg_id, fragq, MSG_FRAG_STATE_DROP == fragq->state);
1373 GNUNET_CONTAINER_heap_remove_root (chn->recv_msgs);
1374 message_queue_run (chn);
1375 break;
1376
1377 default:
1378 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1379 "%p GNUNET_PSYCSTORE_state_modify() failed with error %" PRId64 " (%.*s)\n",
1380 chn, result, err_msg_size, err_msg);
1381 /** @todo FIXME: handle state_modify error */
1382 }
1383}
1384
1385
1386/**
1387 * Run message queue.
1388 *
1389 * Send messages in queue to client in order after a message has arrived from
1390 * multicast, according to the following:
1391 * - A message is only sent if all of its modifiers arrived.
1392 * - A stateful message is only sent if the previous stateful message
1393 * has already been delivered to the client.
1394 *
1395 * @param chn Channel.
1396 *
1397 * @return Number of messages removed from queue and sent to client.
1398 */
1399static uint64_t
1400message_queue_run (struct Channel *chn)
1401{
1402 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1403 "%p Running message queue.\n", chn);
1404 uint64_t n = 0;
1405 uint64_t msg_id;
1406
1407 while (GNUNET_YES == GNUNET_CONTAINER_heap_peek2 (chn->recv_msgs, NULL,
1408 &msg_id))
1409 {
1410 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1411 "%p Processing message %" PRIu64 " in queue.\n", chn, msg_id);
1412 struct GNUNET_HashCode msg_id_hash;
1413 hash_key_from_hll (&msg_id_hash, msg_id);
1414
1415 struct FragmentQueue *
1416 fragq = GNUNET_CONTAINER_multihashmap_get (chn->recv_frags, &msg_id_hash);
1417
1418 if (NULL == fragq || fragq->state <= MSG_FRAG_STATE_HEADER)
1419 {
1420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1421 "%p No fragq (%p) or header not complete.\n",
1422 chn, fragq);
1423 break;
1424 }
1425
1426 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1427 "%p Fragment queue entry: state: %u, state delta: "
1428 "%" PRIu64 " - %" PRIu64 " ?= %" PRIu64 "\n",
1429 chn, fragq->state, msg_id, fragq->state_delta, chn->max_state_message_id);
1430
1431 if (MSG_FRAG_STATE_DATA <= fragq->state)
1432 {
1433 /* Check if there's a missing message before the current one */
1434 if (GNUNET_PSYC_STATE_NOT_MODIFIED == fragq->state_delta)
1435 {
1436 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%p state NOT modified\n", chn);
1437
1438 if (!(fragq->flags & GNUNET_PSYC_MESSAGE_ORDER_ANY)
1439 && (chn->max_message_id != msg_id - 1
1440 && chn->max_message_id != msg_id))
1441 {
1442 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1443 "%p Out of order message. "
1444 "(%" PRIu64 " != %" PRIu64 " - 1)\n",
1445 chn, chn->max_message_id, msg_id);
1446 break;
1447 // FIXME: keep track of messages processed in this queue run,
1448 // and only stop after reaching the end
1449 }
1450 }
1451 else
1452 {
1453 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%p state modified\n", chn);
1454 if (GNUNET_YES != fragq->state_is_modified)
1455 {
1456 if (msg_id - fragq->state_delta != chn->max_state_message_id)
1457 {
1458 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1459 "%p Out of order stateful message. "
1460 "(%" PRIu64 " - %" PRIu64 " != %" PRIu64 ")\n",
1461 chn, msg_id, fragq->state_delta, chn->max_state_message_id);
1462 break;
1463 // FIXME: keep track of messages processed in this queue run,
1464 // and only stop after reaching the end
1465 }
1466
1467 struct StateModifyClosure *mcls = GNUNET_malloc (sizeof (*mcls));
1468 mcls->channel = chn;
1469 mcls->msg_id = msg_id;
1470 mcls->msg_id_hash = msg_id_hash;
1471
1472 /* Apply modifiers to state in PSYCstore */
1473 GNUNET_PSYCSTORE_state_modify (store, &chn->pub_key, msg_id,
1474 fragq->state_delta,
1475 store_recv_state_modify_result, mcls);
1476 break; // continue after asynchronous state modify result
1477 }
1478 }
1479 chn->max_message_id = msg_id;
1480 }
1481 fragment_queue_run (chn, msg_id, fragq, MSG_FRAG_STATE_DROP == fragq->state);
1482 GNUNET_CONTAINER_heap_remove_root (chn->recv_msgs);
1483 n++;
1484 }
1485
1486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1487 "%p Removed %" PRIu64 " messages from queue.\n", chn, n);
1488 return n;
1489}
1490
1491
1492/**
1493 * Drop message queue of a channel.
1494 *
1495 * Remove all messages in queue without sending it to clients.
1496 *
1497 * @param chn Channel.
1498 *
1499 * @return Number of messages removed from queue.
1500 */
1501static uint64_t
1502message_queue_drop (struct Channel *chn)
1503{
1504 uint64_t n = 0;
1505 uint64_t msg_id;
1506 while (GNUNET_YES == GNUNET_CONTAINER_heap_peek2 (chn->recv_msgs, NULL,
1507 &msg_id))
1508 {
1509 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1510 "%p Dropping message %" PRIu64 " from queue.\n", chn, msg_id);
1511 struct GNUNET_HashCode msg_id_hash;
1512 hash_key_from_hll (&msg_id_hash, msg_id);
1513
1514 struct FragmentQueue *
1515 fragq = GNUNET_CONTAINER_multihashmap_get (chn->recv_frags, &msg_id_hash);
1516 GNUNET_assert (NULL != fragq);
1517 fragment_queue_run (chn, msg_id, fragq, GNUNET_YES);
1518 GNUNET_CONTAINER_heap_remove_root (chn->recv_msgs);
1519 n++;
1520 }
1521 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1522 "%p Removed %" PRIu64 " messages from queue.\n", chn, n);
1523 return n;
1524}
1525
1526
1527/**
1528 * Received result of GNUNET_PSYCSTORE_fragment_store().
1529 */
1530static void
1531store_recv_fragment_store_result (void *cls, int64_t result,
1532 const char *err_msg, uint16_t err_msg_size)
1533{
1534 struct Channel *chn = cls;
1535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1536 "%p GNUNET_PSYCSTORE_fragment_store() returned %" PRId64 " (%.*s)\n",
1537 chn, result, err_msg_size, err_msg);
1538}
1539
1540
1541/**
1542 * Handle incoming message fragment from multicast.
1543 *
1544 * Store it using PSYCstore and send it to the clients of the channel in order.
1545 */
1546static void
1547mcast_recv_message (void *cls, const struct GNUNET_MULTICAST_MessageHeader *mmsg)
1548{
1549 struct Channel *chn = cls;
1550 uint16_t size = ntohs (mmsg->header.size);
1551
1552 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1553 "%p Received multicast message of size %u. "
1554 "fragment_id=%" PRIu64 ", message_id=%" PRIu64
1555 ", fragment_offset=%" PRIu64 ", flags=%" PRIu64 "\n",
1556 chn, size,
1557 GNUNET_ntohll (mmsg->fragment_id),
1558 GNUNET_ntohll (mmsg->message_id),
1559 GNUNET_ntohll (mmsg->fragment_offset),
1560 GNUNET_ntohll (mmsg->flags));
1561
1562 GNUNET_PSYCSTORE_fragment_store (store, &chn->pub_key, mmsg, 0,
1563 &store_recv_fragment_store_result, chn);
1564
1565 uint16_t first_ptype = 0, last_ptype = 0;
1566 int check = GNUNET_PSYC_receive_check_parts (size - sizeof (*mmsg),
1567 (const char *) &mmsg[1],
1568 &first_ptype, &last_ptype);
1569 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1570 "%p Message check result %d, first part type %u, last part type %u\n",
1571 chn, check, first_ptype, last_ptype);
1572 if (GNUNET_SYSERR == check)
1573 {
1574 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1575 "%p Dropping incoming multicast message with invalid parts.\n",
1576 chn);
1577 GNUNET_break_op (0);
1578 return;
1579 }
1580
1581 fragment_queue_insert (chn, mmsg, first_ptype, last_ptype);
1582 message_queue_run (chn);
1583}
1584
1585
1586/**
1587 * Incoming request fragment from multicast for a master.
1588 *
1589 * @param cls Master.
1590 * @param req The request.
1591 */
1592static void
1593mcast_recv_request (void *cls,
1594 const struct GNUNET_MULTICAST_RequestHeader *req)
1595{
1596 struct Master *mst = cls;
1597 uint16_t size = ntohs (req->header.size);
1598
1599 char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&req->member_pub_key);
1600 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1601 "%p Received multicast request of size %u from %s.\n",
1602 mst, size, str);
1603 GNUNET_free (str);
1604
1605 uint16_t first_ptype = 0, last_ptype = 0;
1606 if (GNUNET_SYSERR
1607 == GNUNET_PSYC_receive_check_parts (size - sizeof (*req),
1608 (const char *) &req[1],
1609 &first_ptype, &last_ptype))
1610 {
1611 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1612 "%p Dropping incoming multicast request with invalid parts.\n",
1613 mst);
1614 GNUNET_break_op (0);
1615 return;
1616 }
1617
1618 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1619 "Message parts: first: type %u, last: type %u\n",
1620 first_ptype, last_ptype);
1621
1622 /* FIXME: in-order delivery */
1623 client_send_mcast_req (mst, req);
1624}
1625
1626
1627/**
1628 * Response from PSYCstore with the current counter values for a channel master.
1629 */
1630static void
1631store_recv_master_counters (void *cls, int result, uint64_t max_fragment_id,
1632 uint64_t max_message_id, uint64_t max_group_generation,
1633 uint64_t max_state_message_id)
1634{
1635 struct Master *mst = cls;
1636 struct Channel *chn = &mst->channel;
1637 chn->store_op = NULL;
1638
1639 struct GNUNET_PSYC_CountersResultMessage res;
1640 res.header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MASTER_START_ACK);
1641 res.header.size = htons (sizeof (res));
1642 res.result_code = htonl (result);
1643 res.max_message_id = GNUNET_htonll (max_message_id);
1644
1645 if (GNUNET_OK == result || GNUNET_NO == result)
1646 {
1647 mst->max_message_id = max_message_id;
1648 chn->max_message_id = max_message_id;
1649 chn->max_state_message_id = max_state_message_id;
1650 mst->max_group_generation = max_group_generation;
1651 mst->origin
1652 = GNUNET_MULTICAST_origin_start (cfg, &mst->priv_key, max_fragment_id,
1653 mcast_recv_join_request,
1654 mcast_recv_replay_fragment,
1655 mcast_recv_replay_message,
1656 mcast_recv_request,
1657 mcast_recv_message, chn);
1658 chn->is_ready = GNUNET_YES;
1659 }
1660 else
1661 {
1662 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1663 "%p GNUNET_PSYCSTORE_counters_get() "
1664 "returned %d for channel %s.\n",
1665 chn, result, GNUNET_h2s (&chn->pub_key_hash));
1666 }
1667
1668 client_send_msg (chn, &res.header);
1669}
1670
1671
1672/**
1673 * Response from PSYCstore with the current counter values for a channel slave.
1674 */
1675void
1676store_recv_slave_counters (void *cls, int result, uint64_t max_fragment_id,
1677 uint64_t max_message_id, uint64_t max_group_generation,
1678 uint64_t max_state_message_id)
1679{
1680 struct Slave *slv = cls;
1681 struct Channel *chn = &slv->channel;
1682 chn->store_op = NULL;
1683
1684 struct GNUNET_PSYC_CountersResultMessage res;
1685 res.header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN_ACK);
1686 res.header.size = htons (sizeof (res));
1687 res.result_code = htonl (result);
1688 res.max_message_id = GNUNET_htonll (max_message_id);
1689
1690 if (GNUNET_YES == result || GNUNET_NO == result)
1691 {
1692 chn->max_message_id = max_message_id;
1693 chn->max_state_message_id = max_state_message_id;
1694 slv->member
1695 = GNUNET_MULTICAST_member_join (cfg, &chn->pub_key, &slv->priv_key,
1696 &slv->origin,
1697 slv->relay_count, slv->relays,
1698 &slv->join_msg->header,
1699 mcast_recv_join_request,
1700 mcast_recv_join_decision,
1701 mcast_recv_replay_fragment,
1702 mcast_recv_replay_message,
1703 mcast_recv_message, chn);
1704 if (NULL != slv->join_msg)
1705 {
1706 GNUNET_free (slv->join_msg);
1707 slv->join_msg = NULL;
1708 }
1709 }
1710 else
1711 {
1712 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1713 "%p GNUNET_PSYCSTORE_counters_get() "
1714 "returned %d for channel %s.\n",
1715 chn, result, GNUNET_h2s (&chn->pub_key_hash));
1716 }
1717
1718 client_send_msg (chn, &res.header);
1719}
1720
1721
1722static void
1723channel_init (struct Channel *chn)
1724{
1725 chn->recv_msgs
1726 = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1727 chn->recv_frags = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1728}
1729
1730
1731/**
1732 * Handle a connecting client starting a channel master.
1733 */
1734static void
1735handle_client_master_start (void *cls,
1736 const struct MasterStartRequest *req)
1737{
1738 struct Client *c = cls;
1739 struct GNUNET_SERVICE_Client *client = c->client;
1740
1741 struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
1742 struct GNUNET_HashCode pub_key_hash;
1743
1744 GNUNET_CRYPTO_eddsa_key_get_public (&req->channel_key, &pub_key);
1745 GNUNET_CRYPTO_hash (&pub_key, sizeof (pub_key), &pub_key_hash);
1746
1747 struct Master *
1748 mst = GNUNET_CONTAINER_multihashmap_get (masters, &pub_key_hash);
1749 struct Channel *chn;
1750
1751 if (NULL == mst)
1752 {
1753 mst = GNUNET_malloc (sizeof (*mst));
1754 mst->policy = ntohl (req->policy);
1755 mst->priv_key = req->channel_key;
1756 mst->join_reqs = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1757
1758 chn = c->channel = &mst->channel;
1759 chn->master = mst;
1760 chn->is_master = GNUNET_YES;
1761 chn->pub_key = pub_key;
1762 chn->pub_key_hash = pub_key_hash;
1763 channel_init (chn);
1764
1765 GNUNET_CONTAINER_multihashmap_put (masters, &chn->pub_key_hash, chn,
1766 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1767 chn->store_op = GNUNET_PSYCSTORE_counters_get (store, &chn->pub_key,
1768 store_recv_master_counters, mst);
1769 }
1770 else
1771 {
1772 chn = &mst->channel;
1773
1774 struct GNUNET_PSYC_CountersResultMessage *res;
1775 struct GNUNET_MQ_Envelope *
1776 env = GNUNET_MQ_msg (res, GNUNET_MESSAGE_TYPE_PSYC_MASTER_START_ACK);
1777 res->result_code = htonl (GNUNET_OK);
1778 res->max_message_id = GNUNET_htonll (mst->max_message_id);
1779
1780 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
1781 }
1782
1783 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1784 "%p Client connected as master to channel %s.\n",
1785 mst, GNUNET_h2s (&chn->pub_key_hash));
1786
1787 struct ClientList *cli = GNUNET_malloc (sizeof (*cli));
1788 cli->client = client;
1789 GNUNET_CONTAINER_DLL_insert (chn->clients_head, chn->clients_tail, cli);
1790
1791 GNUNET_SERVICE_client_continue (client);
1792}
1793
1794
1795static int
1796check_client_slave_join (void *cls,
1797 const struct SlaveJoinRequest *req)
1798{
1799 return GNUNET_OK;
1800}
1801
1802
1803/**
1804 * Handle a connecting client joining as a channel slave.
1805 */
1806static void
1807handle_client_slave_join (void *cls,
1808 const struct SlaveJoinRequest *req)
1809{
1810 struct Client *c = cls;
1811 struct GNUNET_SERVICE_Client *client = c->client;
1812
1813 uint16_t req_size = ntohs (req->header.size);
1814
1815 struct GNUNET_CRYPTO_EcdsaPublicKey slv_pub_key;
1816 struct GNUNET_HashCode pub_key_hash, slv_pub_hash;
1817
1818 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1819 "got join request from client %p\n",
1820 client);
1821 GNUNET_CRYPTO_ecdsa_key_get_public (&req->slave_key, &slv_pub_key);
1822 GNUNET_CRYPTO_hash (&slv_pub_key, sizeof (slv_pub_key), &slv_pub_hash);
1823 GNUNET_CRYPTO_hash (&req->channel_pub_key, sizeof (req->channel_pub_key), &pub_key_hash);
1824
1825 struct GNUNET_CONTAINER_MultiHashMap *
1826 chn_slv = GNUNET_CONTAINER_multihashmap_get (channel_slaves, &pub_key_hash);
1827 struct Slave *slv = NULL;
1828 struct Channel *chn;
1829
1830 if (NULL != chn_slv)
1831 {
1832 slv = GNUNET_CONTAINER_multihashmap_get (chn_slv, &slv_pub_hash);
1833 }
1834 if (NULL == slv)
1835 {
1836 slv = GNUNET_malloc (sizeof (*slv));
1837 slv->priv_key = req->slave_key;
1838 slv->pub_key = slv_pub_key;
1839 slv->pub_key_hash = slv_pub_hash;
1840 slv->origin = req->origin;
1841 slv->relay_count = ntohl (req->relay_count);
1842 slv->join_flags = ntohl (req->flags);
1843
1844 const struct GNUNET_PeerIdentity *
1845 relays = (const struct GNUNET_PeerIdentity *) &req[1];
1846 uint16_t relay_size = slv->relay_count * sizeof (*relays);
1847 uint16_t join_msg_size = 0;
1848
1849 if (sizeof (*req) + relay_size + sizeof (struct GNUNET_MessageHeader)
1850 <= req_size)
1851 {
1852 struct GNUNET_PSYC_Message *
1853 join_msg = (struct GNUNET_PSYC_Message *) (((char *) &req[1]) + relay_size);
1854 join_msg_size = ntohs (join_msg->header.size);
1855 slv->join_msg = GNUNET_malloc (join_msg_size);
1856 GNUNET_memcpy (slv->join_msg, join_msg, join_msg_size);
1857 }
1858 if (sizeof (*req) + relay_size + join_msg_size != req_size)
1859 {
1860 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1861 "%u + %u + %u != %u\n",
1862 (unsigned int) sizeof (*req),
1863 relay_size,
1864 join_msg_size,
1865 req_size);
1866 GNUNET_break (0);
1867 GNUNET_SERVICE_client_drop (client);
1868 GNUNET_free (slv);
1869 return;
1870 }
1871 if (0 < slv->relay_count)
1872 {
1873 slv->relays = GNUNET_malloc (relay_size);
1874 GNUNET_memcpy (slv->relays, &req[1], relay_size);
1875 }
1876
1877 chn = c->channel = &slv->channel;
1878 chn->slave = slv;
1879 chn->is_master = GNUNET_NO;
1880 chn->pub_key = req->channel_pub_key;
1881 chn->pub_key_hash = pub_key_hash;
1882 channel_init (chn);
1883
1884 if (NULL == chn_slv)
1885 {
1886 chn_slv = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
1887 GNUNET_CONTAINER_multihashmap_put (channel_slaves, &chn->pub_key_hash, chn_slv,
1888 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1889 }
1890 GNUNET_CONTAINER_multihashmap_put (chn_slv, &slv->pub_key_hash, chn,
1891 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1892 GNUNET_CONTAINER_multihashmap_put (slaves, &chn->pub_key_hash, chn,
1893 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1894 chn->store_op = GNUNET_PSYCSTORE_counters_get (store, &chn->pub_key,
1895 &store_recv_slave_counters, slv);
1896 }
1897 else
1898 {
1899 chn = &slv->channel;
1900
1901 struct GNUNET_PSYC_CountersResultMessage *res;
1902
1903 struct GNUNET_MQ_Envelope *
1904 env = GNUNET_MQ_msg (res, GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN_ACK);
1905 res->result_code = htonl (GNUNET_OK);
1906 res->max_message_id = GNUNET_htonll (chn->max_message_id);
1907
1908 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
1909
1910 if (GNUNET_PSYC_SLAVE_JOIN_LOCAL & slv->join_flags)
1911 {
1912 mcast_recv_join_decision (slv, GNUNET_YES,
1913 NULL, 0, NULL, NULL);
1914 }
1915 else if (NULL == slv->member)
1916 {
1917 slv->member
1918 = GNUNET_MULTICAST_member_join (cfg, &chn->pub_key, &slv->priv_key,
1919 &slv->origin,
1920 slv->relay_count, slv->relays,
1921 &slv->join_msg->header,
1922 &mcast_recv_join_request,
1923 &mcast_recv_join_decision,
1924 &mcast_recv_replay_fragment,
1925 &mcast_recv_replay_message,
1926 &mcast_recv_message, chn);
1927 if (NULL != slv->join_msg)
1928 {
1929 GNUNET_free (slv->join_msg);
1930 slv->join_msg = NULL;
1931 }
1932 }
1933 else if (NULL != slv->join_dcsn)
1934 {
1935 struct GNUNET_MQ_Envelope *
1936 env = GNUNET_MQ_msg_copy (&slv->join_dcsn->header);
1937 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
1938 }
1939 }
1940
1941 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1942 "Client %p connected as slave to channel %s.\n",
1943 client,
1944 GNUNET_h2s (&chn->pub_key_hash));
1945
1946 struct ClientList *cli = GNUNET_malloc (sizeof (*cli));
1947 cli->client = client;
1948 GNUNET_CONTAINER_DLL_insert (chn->clients_head, chn->clients_tail, cli);
1949
1950 GNUNET_SERVICE_client_continue (client);
1951}
1952
1953
1954struct JoinDecisionClosure
1955{
1956 int32_t is_admitted;
1957 struct GNUNET_MessageHeader *msg;
1958};
1959
1960
1961/**
1962 * Iterator callback for sending join decisions to multicast.
1963 */
1964static int
1965mcast_send_join_decision (void *cls, const struct GNUNET_HashCode *pub_key_hash,
1966 void *value)
1967{
1968 struct JoinDecisionClosure *jcls = cls;
1969 struct GNUNET_MULTICAST_JoinHandle *jh = value;
1970 // FIXME: add relays
1971 GNUNET_MULTICAST_join_decision (jh, jcls->is_admitted, 0, NULL, jcls->msg);
1972 return GNUNET_YES;
1973}
1974
1975
1976static int
1977check_client_join_decision (void *cls,
1978 const struct GNUNET_PSYC_JoinDecisionMessage *dcsn)
1979{
1980 return GNUNET_OK;
1981}
1982
1983
1984/**
1985 * Join decision from client.
1986 */
1987static void
1988handle_client_join_decision (void *cls,
1989 const struct GNUNET_PSYC_JoinDecisionMessage *dcsn)
1990{
1991 struct Client *c = cls;
1992 struct GNUNET_SERVICE_Client *client = c->client;
1993 struct Channel *chn = c->channel;
1994 if (NULL == chn)
1995 {
1996 GNUNET_break (0);
1997 GNUNET_SERVICE_client_drop (client);
1998 return;
1999 }
2000 GNUNET_assert (GNUNET_YES == chn->is_master);
2001 struct Master *mst = chn->master;
2002
2003 struct JoinDecisionClosure jcls;
2004 jcls.is_admitted = ntohl (dcsn->is_admitted);
2005 jcls.msg
2006 = (sizeof (*dcsn) + sizeof (*jcls.msg) <= ntohs (dcsn->header.size))
2007 ? (struct GNUNET_MessageHeader *) &dcsn[1]
2008 : NULL;
2009
2010 struct GNUNET_HashCode slave_pub_hash;
2011 GNUNET_CRYPTO_hash (&dcsn->slave_pub_key, sizeof (dcsn->slave_pub_key),
2012 &slave_pub_hash);
2013
2014 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2015 "%p Got join decision (%d) from client for channel %s..\n",
2016 mst, jcls.is_admitted, GNUNET_h2s (&chn->pub_key_hash));
2017 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2018 "%p ..and slave %s.\n",
2019 mst, GNUNET_h2s (&slave_pub_hash));
2020
2021 GNUNET_CONTAINER_multihashmap_get_multiple (mst->join_reqs, &slave_pub_hash,
2022 &mcast_send_join_decision, &jcls);
2023 GNUNET_CONTAINER_multihashmap_remove_all (mst->join_reqs, &slave_pub_hash);
2024 GNUNET_SERVICE_client_continue (client);
2025}
2026
2027
2028static void
2029channel_part_cb (void *cls)
2030{
2031 struct GNUNET_SERVICE_Client *client = cls;
2032 struct GNUNET_MQ_Envelope *env;
2033
2034 env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_PSYC_PART_ACK);
2035 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
2036 env);
2037}
2038
2039
2040static void
2041handle_client_part_request (void *cls,
2042 const struct GNUNET_MessageHeader *msg)
2043{
2044 struct Client *c = cls;
2045
2046 c->channel->is_disconnecting = GNUNET_YES;
2047 if (GNUNET_YES == c->channel->is_master)
2048 {
2049 struct Master *mst = (struct Master *) c->channel;
2050
2051 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2052 "Got part request from master %p\n",
2053 mst);
2054 GNUNET_assert (NULL != mst->origin);
2055 GNUNET_MULTICAST_origin_stop (mst->origin, channel_part_cb, c->client);
2056 }
2057 else
2058 {
2059 struct Slave *slv = (struct Slave *) c->channel;
2060
2061 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2062 "Got part request from slave %p\n",
2063 slv);
2064 GNUNET_assert (NULL != slv->member);
2065 GNUNET_MULTICAST_member_part (slv->member, channel_part_cb, c->client);
2066 }
2067 GNUNET_SERVICE_client_continue (c->client);
2068}
2069
2070
2071/**
2072 * Send acknowledgement to a client.
2073 *
2074 * Sent after a message fragment has been passed on to multicast.
2075 *
2076 * @param chn The channel struct for the client.
2077 */
2078static void
2079send_message_ack (struct Channel *chn, struct GNUNET_SERVICE_Client *client)
2080{
2081 struct GNUNET_MessageHeader *res;
2082 struct GNUNET_MQ_Envelope *
2083 env = GNUNET_MQ_msg (res, GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK);
2084
2085 /* FIXME? */
2086 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
2087}
2088
2089
2090/**
2091 * Callback for the transmit functions of multicast.
2092 */
2093static int
2094transmit_notify (void *cls, size_t *data_size, void *data)
2095{
2096 struct Channel *chn = cls;
2097 struct TransmitMessage *tmit_msg = chn->tmit_head;
2098
2099 if (NULL == tmit_msg || *data_size < tmit_msg->size)
2100 {
2101 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2102 "%p transmit_notify: nothing to send.\n", chn);
2103 if (NULL != tmit_msg && *data_size < tmit_msg->size)
2104 GNUNET_break (0);
2105 *data_size = 0;
2106 return GNUNET_NO;
2107 }
2108
2109 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2110 "%p transmit_notify: sending %u bytes.\n", chn, tmit_msg->size);
2111
2112 *data_size = tmit_msg->size;
2113 GNUNET_memcpy (data, &tmit_msg[1], *data_size);
2114
2115 int ret
2116 = (tmit_msg->last_ptype < GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END)
2117 ? GNUNET_NO
2118 : GNUNET_YES;
2119
2120 /* FIXME: handle disconnecting clients */
2121 if (NULL != tmit_msg->client)
2122 send_message_ack (chn, tmit_msg->client);
2123
2124 GNUNET_CONTAINER_DLL_remove (chn->tmit_head, chn->tmit_tail, tmit_msg);
2125
2126 if (NULL != chn->tmit_head)
2127 {
2128 GNUNET_SCHEDULER_add_now (&schedule_transmit_message, chn);
2129 }
2130 else if (GNUNET_YES == chn->is_disconnecting
2131 && tmit_msg->last_ptype < GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END)
2132 {
2133 /* FIXME: handle partial message (when still in_transmit) */
2134 GNUNET_free (tmit_msg);
2135 return GNUNET_SYSERR;
2136 }
2137 GNUNET_free (tmit_msg);
2138 return ret;
2139}
2140
2141
2142/**
2143 * Callback for the transmit functions of multicast.
2144 */
2145static int
2146master_transmit_notify (void *cls, size_t *data_size, void *data)
2147{
2148 int ret = transmit_notify (cls, data_size, data);
2149
2150 if (GNUNET_YES == ret)
2151 {
2152 struct Master *mst = cls;
2153 mst->tmit_handle = NULL;
2154 }
2155 return ret;
2156}
2157
2158
2159/**
2160 * Callback for the transmit functions of multicast.
2161 */
2162static int
2163slave_transmit_notify (void *cls, size_t *data_size, void *data)
2164{
2165 int ret = transmit_notify (cls, data_size, data);
2166
2167 if (GNUNET_YES == ret)
2168 {
2169 struct Slave *slv = cls;
2170 slv->tmit_handle = NULL;
2171 }
2172 return ret;
2173}
2174
2175
2176/**
2177 * Transmit a message from a channel master to the multicast group.
2178 */
2179static void
2180master_transmit_message (struct Master *mst)
2181{
2182 struct Channel *chn = &mst->channel;
2183 struct TransmitMessage *tmit_msg = chn->tmit_head;
2184 if (NULL == tmit_msg)
2185 return;
2186 if (NULL == mst->tmit_handle)
2187 {
2188 mst->tmit_handle = GNUNET_MULTICAST_origin_to_all (mst->origin,
2189 tmit_msg->id,
2190 mst->max_group_generation,
2191 &master_transmit_notify,
2192 mst);
2193 }
2194 else
2195 {
2196 GNUNET_MULTICAST_origin_to_all_resume (mst->tmit_handle);
2197 }
2198}
2199
2200
2201/**
2202 * Transmit a message from a channel slave to the multicast group.
2203 */
2204static void
2205slave_transmit_message (struct Slave *slv)
2206{
2207 if (NULL == slv->channel.tmit_head)
2208 return;
2209 if (NULL == slv->tmit_handle)
2210 {
2211 slv->tmit_handle = GNUNET_MULTICAST_member_to_origin (slv->member,
2212 slv->channel.tmit_head->id,
2213 &slave_transmit_notify,
2214 slv);
2215 }
2216 else
2217 {
2218 GNUNET_MULTICAST_member_to_origin_resume (slv->tmit_handle);
2219 }
2220}
2221
2222
2223static void
2224transmit_message (struct Channel *chn)
2225{
2226 chn->is_master
2227 ? master_transmit_message (chn->master)
2228 : slave_transmit_message (chn->slave);
2229}
2230
2231
2232/**
2233 * Queue a message from a channel master for sending to the multicast group.
2234 */
2235static void
2236master_queue_message (struct Master *mst, struct TransmitMessage *tmit_msg)
2237{
2238 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == tmit_msg->first_ptype)
2239 {
2240 tmit_msg->id = ++mst->max_message_id;
2241 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2242 "%p master_queue_message: message_id=%" PRIu64 "\n",
2243 mst, tmit_msg->id);
2244 struct GNUNET_PSYC_MessageMethod *pmeth
2245 = (struct GNUNET_PSYC_MessageMethod *) &tmit_msg[1];
2246
2247 if (pmeth->flags & GNUNET_PSYC_MASTER_TRANSMIT_STATE_RESET)
2248 {
2249 pmeth->state_delta = GNUNET_htonll (GNUNET_PSYC_STATE_RESET);
2250 }
2251 else if (pmeth->flags & GNUNET_PSYC_MASTER_TRANSMIT_STATE_MODIFY)
2252 {
2253 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2254 "%p master_queue_message: state_delta=%" PRIu64 "\n",
2255 mst, tmit_msg->id - mst->max_state_message_id);
2256 pmeth->state_delta = GNUNET_htonll (tmit_msg->id
2257 - mst->max_state_message_id);
2258 mst->max_state_message_id = tmit_msg->id;
2259 }
2260 else
2261 {
2262 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2263 "%p master_queue_message: state not modified\n", mst);
2264 pmeth->state_delta = GNUNET_htonll (GNUNET_PSYC_STATE_NOT_MODIFIED);
2265 }
2266
2267 if (pmeth->flags & GNUNET_PSYC_MASTER_TRANSMIT_STATE_HASH)
2268 {
2269 /// @todo add state_hash to PSYC header
2270 }
2271 }
2272}
2273
2274
2275/**
2276 * Queue a message from a channel slave for sending to the multicast group.
2277 */
2278static void
2279slave_queue_message (struct Slave *slv, struct TransmitMessage *tmit_msg)
2280{
2281 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == tmit_msg->first_ptype)
2282 {
2283 struct GNUNET_PSYC_MessageMethod *pmeth
2284 = (struct GNUNET_PSYC_MessageMethod *) &tmit_msg[1];
2285 pmeth->state_delta = GNUNET_htonll (GNUNET_PSYC_STATE_NOT_MODIFIED);
2286 tmit_msg->id = ++slv->max_request_id;
2287 }
2288}
2289
2290
2291/**
2292 * Queue PSYC message parts for sending to multicast.
2293 *
2294 * @param chn
2295 * Channel to send to.
2296 * @param client
2297 * Client the message originates from.
2298 * @param data_size
2299 * Size of @a data.
2300 * @param data
2301 * Concatenated message parts.
2302 * @param first_ptype
2303 * First message part type in @a data.
2304 * @param last_ptype
2305 * Last message part type in @a data.
2306 */
2307static struct TransmitMessage *
2308queue_message (struct Channel *chn,
2309 struct GNUNET_SERVICE_Client *client,
2310 size_t data_size,
2311 const void *data,
2312 uint16_t first_ptype, uint16_t last_ptype)
2313{
2314 struct TransmitMessage *
2315 tmit_msg = GNUNET_malloc (sizeof (*tmit_msg) + data_size);
2316 GNUNET_memcpy (&tmit_msg[1], data, data_size);
2317 tmit_msg->client = client;
2318 tmit_msg->size = data_size;
2319 tmit_msg->first_ptype = first_ptype;
2320 tmit_msg->last_ptype = last_ptype;
2321
2322 /* FIXME: separate queue per message ID */
2323
2324 GNUNET_CONTAINER_DLL_insert_tail (chn->tmit_head, chn->tmit_tail, tmit_msg);
2325
2326 chn->is_master
2327 ? master_queue_message (chn->master, tmit_msg)
2328 : slave_queue_message (chn->slave, tmit_msg);
2329 return tmit_msg;
2330}
2331
2332
2333/**
2334 * Cancel transmission of current message.
2335 *
2336 * @param chn Channel to send to.
2337 * @param client Client the message originates from.
2338 */
2339static void
2340transmit_cancel (struct Channel *chn, struct GNUNET_SERVICE_Client *client)
2341{
2342 uint16_t type = GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL;
2343
2344 struct GNUNET_MessageHeader msg;
2345 msg.size = htons (sizeof (msg));
2346 msg.type = htons (type);
2347
2348 queue_message (chn, client, sizeof (msg), &msg, type, type);
2349 transmit_message (chn);
2350
2351 /* FIXME: cleanup */
2352}
2353
2354
2355static int
2356check_client_psyc_message (void *cls,
2357 const struct GNUNET_MessageHeader *msg)
2358{
2359 return GNUNET_OK;
2360}
2361
2362
2363/**
2364 * Incoming message from a master or slave client.
2365 */
2366static void
2367handle_client_psyc_message (void *cls,
2368 const struct GNUNET_MessageHeader *msg)
2369{
2370 struct Client *c = cls;
2371 struct GNUNET_SERVICE_Client *client = c->client;
2372 struct Channel *chn = c->channel;
2373 if (NULL == chn)
2374 {
2375 GNUNET_break (0);
2376 GNUNET_SERVICE_client_drop (client);
2377 return;
2378 }
2379
2380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2381 "%p Received message from client.\n", chn);
2382 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, msg);
2383
2384 if (GNUNET_YES != chn->is_ready)
2385 {
2386 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2387 "%p Channel is not ready yet, disconnecting client %p.\n",
2388 chn,
2389 client);
2390 GNUNET_break (0);
2391 GNUNET_SERVICE_client_drop (client);
2392 return;
2393 }
2394
2395 uint16_t size = ntohs (msg->size);
2396 if (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < size - sizeof (*msg))
2397 {
2398 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2399 "%p Message payload too large: %u < %u.\n",
2400 chn,
2401 (unsigned int) GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD,
2402 (unsigned int) (size - sizeof (*msg)));
2403 GNUNET_break (0);
2404 transmit_cancel (chn, client);
2405 GNUNET_SERVICE_client_drop (client);
2406 return;
2407 }
2408
2409 uint16_t first_ptype = 0, last_ptype = 0;
2410 if (GNUNET_SYSERR
2411 == GNUNET_PSYC_receive_check_parts (size - sizeof (*msg),
2412 (const char *) &msg[1],
2413 &first_ptype, &last_ptype))
2414 {
2415 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2416 "%p Received invalid message part from client.\n", chn);
2417 GNUNET_break (0);
2418 transmit_cancel (chn, client);
2419 GNUNET_SERVICE_client_drop (client);
2420 return;
2421 }
2422 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2423 "%p Received message with first part type %u and last part type %u.\n",
2424 chn, first_ptype, last_ptype);
2425
2426 queue_message (chn, client, size - sizeof (*msg), &msg[1],
2427 first_ptype, last_ptype);
2428 transmit_message (chn);
2429 /* FIXME: send a few ACKs even before transmit_notify is called */
2430
2431 GNUNET_SERVICE_client_continue (client);
2432};
2433
2434
2435/**
2436 * Received result of GNUNET_PSYCSTORE_membership_store()
2437 */
2438static void
2439store_recv_membership_store_result (void *cls,
2440 int64_t result,
2441 const char *err_msg,
2442 uint16_t err_msg_size)
2443{
2444 struct Operation *op = cls;
2445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2446 "%p GNUNET_PSYCSTORE_membership_store() returned %" PRId64 " (%.*s)\n",
2447 op->channel,
2448 result,
2449 (int) err_msg_size,
2450 err_msg);
2451
2452 if (NULL != op->client)
2453 client_send_result (op->client, op->op_id, result, err_msg, err_msg_size);
2454 op_remove (op);
2455}
2456
2457
2458/**
2459 * Client requests to add/remove a slave in the membership database.
2460 */
2461static void
2462handle_client_membership_store (void *cls,
2463 const struct ChannelMembershipStoreRequest *req)
2464{
2465 struct Client *c = cls;
2466 struct GNUNET_SERVICE_Client *client = c->client;
2467 struct Channel *chn = c->channel;
2468 if (NULL == chn)
2469 {
2470 GNUNET_break (0);
2471 GNUNET_SERVICE_client_drop (client);
2472 return;
2473 }
2474
2475 struct Operation *op = op_add (chn, client, req->op_id, 0);
2476
2477 uint64_t announced_at = GNUNET_ntohll (req->announced_at);
2478 uint64_t effective_since = GNUNET_ntohll (req->effective_since);
2479 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2480 "%p Received membership store request from client.\n", chn);
2481 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2482 "%p did_join: %u, announced_at: %" PRIu64 ", effective_since: %" PRIu64 "\n",
2483 chn, req->did_join, announced_at, effective_since);
2484
2485 GNUNET_PSYCSTORE_membership_store (store, &chn->pub_key, &req->slave_pub_key,
2486 req->did_join, announced_at, effective_since,
2487 0, /* FIXME: group_generation */
2488 &store_recv_membership_store_result, op);
2489 GNUNET_SERVICE_client_continue (client);
2490}
2491
2492
2493/**
2494 * Received a fragment for GNUNET_PSYCSTORE_fragment_get(),
2495 * in response to a history request from a client.
2496 */
2497static int
2498store_recv_fragment_history (void *cls,
2499 struct GNUNET_MULTICAST_MessageHeader *mmsg,
2500 enum GNUNET_PSYCSTORE_MessageFlags flags)
2501{
2502 struct Operation *op = cls;
2503 if (NULL == op->client)
2504 { /* Requesting client already disconnected. */
2505 return GNUNET_NO;
2506 }
2507 struct Channel *chn = op->channel;
2508
2509 struct GNUNET_PSYC_MessageHeader *pmsg;
2510 uint16_t msize = ntohs (mmsg->header.size);
2511 uint16_t psize = sizeof (*pmsg) + msize - sizeof (*mmsg);
2512
2513 struct GNUNET_OperationResultMessage *
2514 res = GNUNET_malloc (sizeof (*res) + psize);
2515 res->header.size = htons (sizeof (*res) + psize);
2516 res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT);
2517 res->op_id = op->op_id;
2518 res->result_code = GNUNET_htonll (GNUNET_OK);
2519
2520 pmsg = (struct GNUNET_PSYC_MessageHeader *) &res[1];
2521 GNUNET_PSYC_message_header_init (pmsg, mmsg, flags | GNUNET_PSYC_MESSAGE_HISTORIC);
2522 GNUNET_memcpy (&res[1], pmsg, psize);
2523
2524 /** @todo FIXME: send only to requesting client */
2525 client_send_msg (chn, &res->header);
2526
2527 GNUNET_free (res);
2528 return GNUNET_YES;
2529}
2530
2531
2532/**
2533 * Received the result of GNUNET_PSYCSTORE_fragment_get(),
2534 * in response to a history request from a client.
2535 */
2536static void
2537store_recv_fragment_history_result (void *cls, int64_t result,
2538 const char *err_msg, uint16_t err_msg_size)
2539{
2540 struct Operation *op = cls;
2541 if (NULL == op->client)
2542 { /* Requesting client already disconnected. */
2543 return;
2544 }
2545
2546 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2547 "%p History replay #%" PRIu64 ": "
2548 "PSYCSTORE returned %" PRId64 " (%.*s)\n",
2549 op->channel, GNUNET_ntohll (op->op_id), result, err_msg_size, err_msg);
2550
2551 if (op->flags & GNUNET_PSYC_HISTORY_REPLAY_REMOTE)
2552 {
2553 /** @todo Multicast replay request for messages not found locally. */
2554 }
2555
2556 client_send_result (op->client, op->op_id, result, err_msg, err_msg_size);
2557 op_remove (op);
2558}
2559
2560
2561static int
2562check_client_history_replay (void *cls,
2563 const struct GNUNET_PSYC_HistoryRequestMessage *req)
2564{
2565 return GNUNET_OK;
2566}
2567
2568
2569/**
2570 * Client requests channel history.
2571 */
2572static void
2573handle_client_history_replay (void *cls,
2574 const struct GNUNET_PSYC_HistoryRequestMessage *req)
2575{
2576 struct Client *c = cls;
2577 struct GNUNET_SERVICE_Client *client = c->client;
2578 struct Channel *chn = c->channel;
2579 if (NULL == chn)
2580 {
2581 GNUNET_break (0);
2582 GNUNET_SERVICE_client_drop (client);
2583 return;
2584 }
2585
2586 uint16_t size = ntohs (req->header.size);
2587 const char *method_prefix = (const char *) &req[1];
2588
2589 if (size < sizeof (*req) + 1
2590 || '\0' != method_prefix[size - sizeof (*req) - 1])
2591 {
2592 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2593 "%p History replay #%" PRIu64 ": "
2594 "invalid method prefix. size: %u < %u?\n",
2595 chn,
2596 GNUNET_ntohll (req->op_id),
2597 size,
2598 (unsigned int) sizeof (*req) + 1);
2599 GNUNET_break (0);
2600 GNUNET_SERVICE_client_drop (client);
2601 return;
2602 }
2603
2604 struct Operation *op = op_add (chn, client, req->op_id, ntohl (req->flags));
2605
2606 if (0 == req->message_limit)
2607 {
2608 GNUNET_PSYCSTORE_message_get (store, &chn->pub_key, NULL,
2609 GNUNET_ntohll (req->start_message_id),
2610 GNUNET_ntohll (req->end_message_id),
2611 0, method_prefix,
2612 &store_recv_fragment_history,
2613 &store_recv_fragment_history_result, op);
2614 }
2615 else
2616 {
2617 GNUNET_PSYCSTORE_message_get_latest (store, &chn->pub_key, NULL,
2618 GNUNET_ntohll (req->message_limit),
2619 method_prefix,
2620 &store_recv_fragment_history,
2621 &store_recv_fragment_history_result,
2622 op);
2623 }
2624 GNUNET_SERVICE_client_continue (client);
2625}
2626
2627
2628/**
2629 * Received state var from PSYCstore, send it to client.
2630 */
2631static int
2632store_recv_state_var (void *cls, const char *name,
2633 const void *value, uint32_t value_size)
2634{
2635 struct Operation *op = cls;
2636 struct GNUNET_OperationResultMessage *res;
2637 struct GNUNET_MQ_Envelope *env;
2638
2639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2640 "%p state_get #%" PRIu64 " - received var from PSYCstore: %s\n",
2641 op->channel, GNUNET_ntohll (op->op_id), name);
2642
2643 if (NULL != name) /* First part */
2644 {
2645 uint16_t name_size = strnlen (name, GNUNET_PSYC_MODIFIER_MAX_PAYLOAD) + 1;
2646 struct GNUNET_PSYC_MessageModifier *mod;
2647 env = GNUNET_MQ_msg_extra (res,
2648 sizeof (*mod) + name_size + value_size,
2649 GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT);
2650 res->op_id = op->op_id;
2651
2652 mod = (struct GNUNET_PSYC_MessageModifier *) &res[1];
2653 mod->header.size = htons (sizeof (*mod) + name_size + value_size);
2654 mod->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER);
2655 mod->name_size = htons (name_size);
2656 mod->value_size = htonl (value_size);
2657 mod->oper = htons (GNUNET_PSYC_OP_ASSIGN);
2658 GNUNET_memcpy (&mod[1], name, name_size);
2659 GNUNET_memcpy (((char *) &mod[1]) + name_size, value, value_size);
2660 }
2661 else /* Continuation */
2662 {
2663 struct GNUNET_MessageHeader *mod;
2664 env = GNUNET_MQ_msg_extra (res,
2665 sizeof (*mod) + value_size,
2666 GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT);
2667 res->op_id = op->op_id;
2668
2669 mod = (struct GNUNET_MessageHeader *) &res[1];
2670 mod->size = htons (sizeof (*mod) + value_size);
2671 mod->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT);
2672 GNUNET_memcpy (&mod[1], value, value_size);
2673 }
2674
2675 // FIXME: client might have been disconnected
2676 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (op->client), env);
2677 return GNUNET_YES;
2678}
2679
2680
2681/**
2682 * Received result of GNUNET_PSYCSTORE_state_get()
2683 * or GNUNET_PSYCSTORE_state_get_prefix()
2684 */
2685static void
2686store_recv_state_result (void *cls, int64_t result,
2687 const char *err_msg, uint16_t err_msg_size)
2688{
2689 struct Operation *op = cls;
2690 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2691 "%p state_get #%" PRIu64 ": "
2692 "PSYCSTORE returned %" PRId64 " (%.*s)\n",
2693 op->channel, GNUNET_ntohll (op->op_id), result, err_msg_size, err_msg);
2694
2695 // FIXME: client might have been disconnected
2696 client_send_result (op->client, op->op_id, result, err_msg, err_msg_size);
2697 op_remove (op);
2698}
2699
2700
2701static int
2702check_client_state_get (void *cls,
2703 const struct StateRequest *req)
2704{
2705 struct Client *c = cls;
2706 struct Channel *chn = c->channel;
2707 if (NULL == chn)
2708 {
2709 GNUNET_break (0);
2710 return GNUNET_SYSERR;
2711 }
2712
2713 uint16_t name_size = ntohs (req->header.size) - sizeof (*req);
2714 const char *name = (const char *) &req[1];
2715 if (0 == name_size || '\0' != name[name_size - 1])
2716 {
2717 GNUNET_break (0);
2718 return GNUNET_SYSERR;
2719 }
2720
2721 return GNUNET_OK;
2722}
2723
2724
2725/**
2726 * Client requests best matching state variable from PSYCstore.
2727 */
2728static void
2729handle_client_state_get (void *cls,
2730 const struct StateRequest *req)
2731{
2732 struct Client *c = cls;
2733 struct GNUNET_SERVICE_Client *client = c->client;
2734 struct Channel *chn = c->channel;
2735
2736 const char *name = (const char *) &req[1];
2737 struct Operation *op = op_add (chn, client, req->op_id, 0);
2738 GNUNET_PSYCSTORE_state_get (store, &chn->pub_key, name,
2739 &store_recv_state_var,
2740 &store_recv_state_result, op);
2741 GNUNET_SERVICE_client_continue (client);
2742}
2743
2744
2745static int
2746check_client_state_get_prefix (void *cls,
2747 const struct StateRequest *req)
2748{
2749 struct Client *c = cls;
2750 struct Channel *chn = c->channel;
2751 if (NULL == chn)
2752 {
2753 GNUNET_break (0);
2754 return GNUNET_SYSERR;
2755 }
2756
2757 uint16_t name_size = ntohs (req->header.size) - sizeof (*req);
2758 const char *name = (const char *) &req[1];
2759 if (0 == name_size || '\0' != name[name_size - 1])
2760 {
2761 GNUNET_break (0);
2762 return GNUNET_SYSERR;
2763 }
2764
2765 return GNUNET_OK;
2766}
2767
2768
2769/**
2770 * Client requests state variables with a given prefix from PSYCstore.
2771 */
2772static void
2773handle_client_state_get_prefix (void *cls,
2774 const struct StateRequest *req)
2775{
2776 struct Client *c = cls;
2777 struct GNUNET_SERVICE_Client *client = c->client;
2778 struct Channel *chn = c->channel;
2779
2780 const char *name = (const char *) &req[1];
2781 struct Operation *op = op_add (chn, client, req->op_id, 0);
2782 GNUNET_PSYCSTORE_state_get_prefix (store, &chn->pub_key, name,
2783 &store_recv_state_var,
2784 &store_recv_state_result, op);
2785 GNUNET_SERVICE_client_continue (client);
2786}
2787
2788
2789/**
2790 * Initialize the PSYC service.
2791 *
2792 * @param cls Closure.
2793 * @param server The initialized server.
2794 * @param c Configuration to use.
2795 */
2796static void
2797run (void *cls,
2798 const struct GNUNET_CONFIGURATION_Handle *c,
2799 struct GNUNET_SERVICE_Handle *svc)
2800{
2801 cfg = c;
2802 service = svc;
2803 store = GNUNET_PSYCSTORE_connect (cfg);
2804 stats = GNUNET_STATISTICS_create ("psyc", cfg);
2805 masters = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2806 slaves = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
2807 channel_slaves = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2808 recv_cache = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2809 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
2810}
2811
2812
2813/**
2814 * Define "main" method using service macro.
2815 */
2816GNUNET_SERVICE_MAIN
2817("psyc",
2818 GNUNET_SERVICE_OPTION_NONE,
2819 &run,
2820 &client_notify_connect,
2821 &client_notify_disconnect,
2822 NULL,
2823 GNUNET_MQ_hd_fixed_size (client_master_start,
2824 GNUNET_MESSAGE_TYPE_PSYC_MASTER_START,
2825 struct MasterStartRequest,
2826 NULL),
2827 GNUNET_MQ_hd_var_size (client_slave_join,
2828 GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN,
2829 struct SlaveJoinRequest,
2830 NULL),
2831 GNUNET_MQ_hd_var_size (client_join_decision,
2832 GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION,
2833 struct GNUNET_PSYC_JoinDecisionMessage,
2834 NULL),
2835 GNUNET_MQ_hd_fixed_size (client_part_request,
2836 GNUNET_MESSAGE_TYPE_PSYC_PART_REQUEST,
2837 struct GNUNET_MessageHeader,
2838 NULL),
2839 GNUNET_MQ_hd_var_size (client_psyc_message,
2840 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE,
2841 struct GNUNET_MessageHeader,
2842 NULL),
2843 GNUNET_MQ_hd_fixed_size (client_membership_store,
2844 GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_MEMBERSHIP_STORE,
2845 struct ChannelMembershipStoreRequest,
2846 NULL),
2847 GNUNET_MQ_hd_var_size (client_history_replay,
2848 GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY,
2849 struct GNUNET_PSYC_HistoryRequestMessage,
2850 NULL),
2851 GNUNET_MQ_hd_var_size (client_state_get,
2852 GNUNET_MESSAGE_TYPE_PSYC_STATE_GET,
2853 struct StateRequest,
2854 NULL),
2855 GNUNET_MQ_hd_var_size (client_state_get_prefix,
2856 GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX,
2857 struct StateRequest,
2858 NULL));
2859
2860/* 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 @@
1[psyc]
2START_ON_DEMAND = @START_ON_DEMAND@
3BINARY = gnunet-service-psyc
4
5UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-psyc.sock
6UNIX_MATCH_UID = YES
7UNIX_MATCH_GID = YES
8
9@UNIXONLY@PORT = 2115
10HOSTNAME = localhost
11ACCEPT_FROM = 127.0.0.1;
12ACCEPT_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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file psyc/psyc.h
23 * @brief Common type definitions for the PSYC service and API.
24 * @author Gabor X Toth
25 */
26
27#ifndef PSYC_H
28#define PSYC_H
29
30#include "platform.h"
31#include "gnunet_psyc_service.h"
32
33
34int
35GNUNET_PSYC_check_message_parts (uint16_t data_size, const char *data,
36 uint16_t *first_ptype, uint16_t *last_ptype);
37
38void
39GNUNET_PSYC_log_message (enum GNUNET_ErrorType kind,
40 const struct GNUNET_MessageHeader *msg);
41
42
43enum MessageState
44{
45 MSG_STATE_START = 0,
46 MSG_STATE_HEADER = 1,
47 MSG_STATE_METHOD = 2,
48 MSG_STATE_MODIFIER = 3,
49 MSG_STATE_MOD_CONT = 4,
50 MSG_STATE_DATA = 5,
51 MSG_STATE_END = 6,
52 MSG_STATE_CANCEL = 7,
53 MSG_STATE_ERROR = 8,
54};
55
56
57enum MessageFragmentState
58{
59 MSG_FRAG_STATE_START = 0,
60 MSG_FRAG_STATE_HEADER = 1,
61 MSG_FRAG_STATE_DATA = 2,
62 MSG_FRAG_STATE_END = 3,
63 MSG_FRAG_STATE_CANCEL = 4,
64 MSG_FRAG_STATE_DROP = 5,
65};
66
67
68GNUNET_NETWORK_STRUCT_BEGIN
69
70
71/**** library -> service ****/
72
73
74struct MasterStartRequest
75{
76 /**
77 * Type: GNUNET_MESSAGE_TYPE_PSYC_MASTER_START
78 */
79 struct GNUNET_MessageHeader header;
80
81 uint32_t policy GNUNET_PACKED;
82
83 struct GNUNET_CRYPTO_EddsaPrivateKey channel_key;
84};
85
86
87struct SlaveJoinRequest
88{
89 /**
90 * Type: GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN
91 */
92 struct GNUNET_MessageHeader header;
93
94 uint32_t relay_count GNUNET_PACKED;
95
96 struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key;
97
98 struct GNUNET_CRYPTO_EcdsaPrivateKey slave_key;
99
100 struct GNUNET_PeerIdentity origin;
101
102 uint32_t flags GNUNET_PACKED;
103
104 /* Followed by struct GNUNET_PeerIdentity relays[relay_count] */
105
106 /* Followed by struct GNUNET_MessageHeader join_msg */
107};
108
109
110struct ChannelMembershipStoreRequest
111{
112 /**
113 * Type: GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_MEMBERSHIP_STORE
114 */
115 struct GNUNET_MessageHeader header;
116
117 uint32_t reserved GNUNET_PACKED;
118
119 uint64_t op_id GNUNET_PACKED;
120
121 struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key;
122
123 uint64_t announced_at GNUNET_PACKED;
124
125 uint64_t effective_since GNUNET_PACKED;
126
127 uint8_t did_join;
128};
129
130
131struct HistoryRequest
132{
133 /**
134 * Type: GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_HISTORY_REQUEST
135 */
136 struct GNUNET_MessageHeader header;
137
138 uint32_t reserved GNUNET_PACKED;
139
140 /**
141 * ID for this operation.
142 */
143 uint64_t op_id GNUNET_PACKED;
144
145 uint64_t start_message_id GNUNET_PACKED;
146
147 uint64_t end_message_id GNUNET_PACKED;
148
149 uint64_t message_limit GNUNET_PACKED;
150};
151
152
153struct StateRequest
154{
155 /**
156 * Types:
157 * - GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_STATE_GET
158 * - GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_STATE_GET_PREFIX
159 */
160 struct GNUNET_MessageHeader header;
161
162 uint32_t reserved GNUNET_PACKED;
163
164 /**
165 * ID for this operation.
166 */
167 uint64_t op_id GNUNET_PACKED;
168
169 /* Followed by NUL-terminated name. */
170};
171
172
173/**** service -> library ****/
174
175
176GNUNET_NETWORK_STRUCT_END
177
178#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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file psyc/psyc_api.c
23 * @brief PSYC service; high-level access to the PSYC protocol
24 * note that clients of this API are NOT expected to
25 * understand the PSYC message format, only the semantics!
26 * Parsing (and serializing) the PSYC stream format is done
27 * within the implementation of the libgnunetpsyc library,
28 * and this API deliberately exposes as little as possible
29 * of the actual data stream format to the application!
30 * @author Gabor X Toth
31 */
32
33#include <inttypes.h>
34
35#include "platform.h"
36#include "gnunet_util_lib.h"
37#include "gnunet_multicast_service.h"
38#include "gnunet_psyc_service.h"
39#include "gnunet_psyc_util_lib.h"
40#include "psyc.h"
41
42#define LOG(kind,...) GNUNET_log_from (kind, "psyc-api",__VA_ARGS__)
43
44
45/**
46 * Handle to access PSYC channel operations for both the master and slaves.
47 */
48struct GNUNET_PSYC_Channel
49{
50 /**
51 * Configuration to use.
52 */
53 const struct GNUNET_CONFIGURATION_Handle *cfg;
54
55 /**
56 * Client connection to the service.
57 */
58 struct GNUNET_MQ_Handle *mq;
59
60 /**
61 * Message to send on connect.
62 */
63 struct GNUNET_MQ_Envelope *connect_env;
64
65 /**
66 * Time to wait until we try to reconnect on failure.
67 */
68 struct GNUNET_TIME_Relative reconnect_delay;
69
70 /**
71 * Task for reconnecting when the listener fails.
72 */
73 struct GNUNET_SCHEDULER_Task *reconnect_task;
74
75 /**
76 * Async operations.
77 */
78 struct GNUNET_OP_Handle *op;
79
80 /**
81 * Transmission handle;
82 */
83 struct GNUNET_PSYC_TransmitHandle *tmit;
84
85 /**
86 * Receipt handle;
87 */
88 struct GNUNET_PSYC_ReceiveHandle *recv;
89
90 /**
91 * Function called after disconnected from the service.
92 */
93 GNUNET_ContinuationCallback disconnect_cb;
94
95 /**
96 * Closure for @a disconnect_cb.
97 */
98 void *disconnect_cls;
99
100 /**
101 * Are we polling for incoming messages right now?
102 */
103 uint8_t in_receive;
104
105 /**
106 * Is this a master or slave channel?
107 */
108 uint8_t is_master;
109
110 /**
111 * Is this channel in the process of disconnecting from the service?
112 * #GNUNET_YES or #GNUNET_NO
113 */
114 uint8_t is_disconnecting;
115};
116
117
118/**
119 * Handle for the master of a PSYC channel.
120 */
121struct GNUNET_PSYC_Master
122{
123 struct GNUNET_PSYC_Channel chn;
124
125 GNUNET_PSYC_MasterStartCallback start_cb;
126
127 /**
128 * Join request callback.
129 */
130 GNUNET_PSYC_JoinRequestCallback join_req_cb;
131
132 /**
133 * Closure for the callbacks.
134 */
135 void *cb_cls;
136};
137
138
139/**
140 * Handle for a PSYC channel slave.
141 */
142struct GNUNET_PSYC_Slave
143{
144 struct GNUNET_PSYC_Channel chn;
145
146 GNUNET_PSYC_SlaveConnectCallback connect_cb;
147
148 GNUNET_PSYC_JoinDecisionCallback join_dcsn_cb;
149
150 /**
151 * Closure for the callbacks.
152 */
153 void *cb_cls;
154};
155
156
157/**
158 * Handle that identifies a join request.
159 *
160 * Used to match calls to #GNUNET_PSYC_JoinRequestCallback to the
161 * corresponding calls to GNUNET_PSYC_join_decision().
162 */
163struct GNUNET_PSYC_JoinHandle
164{
165 struct GNUNET_PSYC_Master *mst;
166 struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key;
167};
168
169
170/**
171 * Handle for a pending PSYC transmission operation.
172 */
173struct GNUNET_PSYC_SlaveTransmitHandle
174{
175
176};
177
178
179struct GNUNET_PSYC_HistoryRequest
180{
181 /**
182 * Channel.
183 */
184 struct GNUNET_PSYC_Channel *chn;
185
186 /**
187 * Operation ID.
188 */
189 uint64_t op_id;
190
191 /**
192 * Message handler.
193 */
194 struct GNUNET_PSYC_ReceiveHandle *recv;
195
196 /**
197 * Function to call when the operation finished.
198 */
199 GNUNET_ResultCallback result_cb;
200
201 /**
202 * Closure for @a result_cb.
203 */
204 void *cls;
205};
206
207
208struct GNUNET_PSYC_StateRequest
209{
210 /**
211 * Channel.
212 */
213 struct GNUNET_PSYC_Channel *chn;
214
215 /**
216 * Operation ID.
217 */
218 uint64_t op_id;
219
220 /**
221 * State variable result callback.
222 */
223 GNUNET_PSYC_StateVarCallback var_cb;
224
225 /**
226 * Function to call when the operation finished.
227 */
228 GNUNET_ResultCallback result_cb;
229
230 /**
231 * Closure for @a result_cb.
232 */
233 void *cls;
234};
235
236
237static int
238check_channel_result (void *cls,
239 const struct GNUNET_OperationResultMessage *res)
240{
241 return GNUNET_OK;
242}
243
244
245static void
246handle_channel_result (void *cls,
247 const struct GNUNET_OperationResultMessage *res)
248{
249 struct GNUNET_PSYC_Channel *chn = cls;
250
251 uint16_t size = ntohs (res->header.size);
252 if (size < sizeof (*res))
253 { /* Error, message too small. */
254 GNUNET_break (0);
255 return;
256 }
257
258 uint16_t data_size = size - sizeof (*res);
259 const char *data = (0 < data_size) ? (void *) &res[1] : NULL;
260 GNUNET_OP_result (chn->op, GNUNET_ntohll (res->op_id),
261 GNUNET_ntohll (res->result_code),
262 data, data_size, NULL);
263
264 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
265 "handle_channel_result: Received result message with OP ID %" PRIu64 "\n",
266 GNUNET_ntohll (res->op_id));
267}
268
269
270static void
271op_recv_history_result (void *cls, int64_t result,
272 const void *data, uint16_t data_size)
273{
274 LOG (GNUNET_ERROR_TYPE_DEBUG,
275 "Received history replay result: %" PRId64 ".\n", result);
276
277 struct GNUNET_PSYC_HistoryRequest *hist = cls;
278
279 if (NULL != hist->result_cb)
280 hist->result_cb (hist->cls, result, data, data_size);
281
282 GNUNET_PSYC_receive_destroy (hist->recv);
283 GNUNET_free (hist);
284}
285
286
287static void
288op_recv_state_result (void *cls, int64_t result,
289 const void *data, uint16_t data_size)
290{
291 LOG (GNUNET_ERROR_TYPE_DEBUG,
292 "Received state request result: %" PRId64 ".\n", result);
293
294 struct GNUNET_PSYC_StateRequest *sr = cls;
295
296 if (NULL != sr->result_cb)
297 sr->result_cb (sr->cls, result, data, data_size);
298
299 GNUNET_free (sr);
300}
301
302
303static int
304check_channel_history_result (void *cls,
305 const struct GNUNET_OperationResultMessage *res)
306{
307 struct GNUNET_PSYC_MessageHeader *
308 pmsg = (struct GNUNET_PSYC_MessageHeader *) GNUNET_MQ_extract_nested_mh (res);
309 uint16_t size = ntohs (res->header.size);
310
311 if ( (NULL == pmsg) ||
312 (size < sizeof (*res) + sizeof (*pmsg)) )
313 { /* Error, message too small. */
314 GNUNET_break_op (0);
315 return GNUNET_SYSERR;
316 }
317 return GNUNET_OK;
318}
319
320
321static void
322handle_channel_history_result (void *cls,
323 const struct GNUNET_OperationResultMessage *res)
324{
325 struct GNUNET_PSYC_Channel *chn = cls;
326 struct GNUNET_PSYC_MessageHeader *
327 pmsg = (struct GNUNET_PSYC_MessageHeader *) GNUNET_MQ_extract_nested_mh (res);
328 GNUNET_ResultCallback result_cb = NULL;
329 struct GNUNET_PSYC_HistoryRequest *hist = NULL;
330
331 LOG (GNUNET_ERROR_TYPE_DEBUG,
332 "%p Received historic fragment for message #%" PRIu64 ".\n",
333 chn,
334 GNUNET_ntohll (pmsg->message_id));
335
336 if (GNUNET_YES != GNUNET_OP_get (chn->op,
337 GNUNET_ntohll (res->op_id),
338 &result_cb, (void *) &hist, NULL))
339 { /* Operation not found. */
340 LOG (GNUNET_ERROR_TYPE_WARNING,
341 "%p Replay operation not found for historic fragment of message #%"
342 PRIu64 ".\n",
343 chn, GNUNET_ntohll (pmsg->message_id));
344 return;
345 }
346
347 GNUNET_PSYC_receive_message (hist->recv,
348 (const struct GNUNET_PSYC_MessageHeader *) pmsg);
349}
350
351
352static int
353check_channel_state_result (void *cls,
354 const struct GNUNET_OperationResultMessage *res)
355{
356 const struct GNUNET_MessageHeader *mod = GNUNET_MQ_extract_nested_mh (res);
357 uint16_t mod_size;
358 uint16_t size;
359
360 if (NULL == mod)
361 {
362 GNUNET_break_op (0);
363 return GNUNET_SYSERR;
364 }
365 mod_size = ntohs (mod->size);
366 size = ntohs (res->header.size);
367 if (size - sizeof (*res) != mod_size)
368 {
369 GNUNET_break_op (0);
370 return GNUNET_SYSERR;
371 }
372 return GNUNET_OK;
373}
374
375
376static void
377handle_channel_state_result (void *cls,
378 const struct GNUNET_OperationResultMessage *res)
379{
380 struct GNUNET_PSYC_Channel *chn = cls;
381
382 GNUNET_ResultCallback result_cb = NULL;
383 struct GNUNET_PSYC_StateRequest *sr = NULL;
384
385 if (GNUNET_YES != GNUNET_OP_get (chn->op,
386 GNUNET_ntohll (res->op_id),
387 &result_cb, (void *) &sr, NULL))
388 { /* Operation not found. */
389 return;
390 }
391
392 const struct GNUNET_MessageHeader *mod = GNUNET_MQ_extract_nested_mh (res);
393 if (NULL == mod)
394 {
395 GNUNET_break_op (0);
396 return;
397 }
398 uint16_t mod_size = ntohs (mod->size);
399
400 switch (ntohs (mod->type))
401 {
402 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
403 {
404 const struct GNUNET_PSYC_MessageModifier *
405 pmod = (const struct GNUNET_PSYC_MessageModifier *) mod;
406
407 const char *name = (const char *) &pmod[1];
408 uint16_t name_size = ntohs (pmod->name_size);
409 if (0 == name_size
410 || mod_size - sizeof (*pmod) < name_size
411 || '\0' != name[name_size - 1])
412 {
413 GNUNET_break_op (0);
414 return;
415 }
416 sr->var_cb (sr->cls, mod, name, name + name_size,
417 ntohs (pmod->header.size) - sizeof (*pmod),
418 ntohs (pmod->value_size));
419 break;
420 }
421
422 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
423 sr->var_cb (sr->cls, mod, NULL, (const char *) &mod[1],
424 mod_size - sizeof (*mod), 0);
425 break;
426 }
427}
428
429
430static int
431check_channel_message (void *cls,
432 const struct GNUNET_PSYC_MessageHeader *pmsg)
433{
434 return GNUNET_OK;
435}
436
437
438static void
439handle_channel_message (void *cls,
440 const struct GNUNET_PSYC_MessageHeader *pmsg)
441{
442 struct GNUNET_PSYC_Channel *chn = cls;
443
444 GNUNET_PSYC_receive_message (chn->recv, pmsg);
445}
446
447
448static void
449handle_channel_message_ack (void *cls,
450 const struct GNUNET_MessageHeader *msg)
451{
452 struct GNUNET_PSYC_Channel *chn = cls;
453
454 GNUNET_PSYC_transmit_got_ack (chn->tmit);
455}
456
457
458static void
459handle_master_start_ack (void *cls,
460 const struct GNUNET_PSYC_CountersResultMessage *cres)
461{
462 struct GNUNET_PSYC_Master *mst = cls;
463
464 int32_t result = ntohl (cres->result_code);
465 if (GNUNET_OK != result && GNUNET_NO != result)
466 {
467 LOG (GNUNET_ERROR_TYPE_ERROR, "Could not start master: %ld\n", result);
468 GNUNET_break (0);
469 /* FIXME: disconnect */
470 }
471 if (NULL != mst->start_cb)
472 mst->start_cb (mst->cb_cls, result, GNUNET_ntohll (cres->max_message_id));
473}
474
475
476static int
477check_master_join_request (void *cls,
478 const struct GNUNET_PSYC_JoinRequestMessage *req)
479{
480 if ( ((sizeof (*req) + sizeof (struct GNUNET_PSYC_Message)) <= ntohs (req->header.size)) &&
481 (NULL == GNUNET_MQ_extract_nested_mh (req)) )
482 {
483 GNUNET_break_op (0);
484 return GNUNET_SYSERR;
485 }
486 return GNUNET_OK;
487}
488
489
490static void
491handle_master_join_request (void *cls,
492 const struct GNUNET_PSYC_JoinRequestMessage *req)
493{
494 struct GNUNET_PSYC_Master *mst = cls;
495
496 if (NULL == mst->join_req_cb)
497 return;
498
499 const struct GNUNET_PSYC_Message *join_msg = NULL;
500 if (sizeof (*req) + sizeof (*join_msg) <= ntohs (req->header.size))
501 {
502 join_msg = (struct GNUNET_PSYC_Message *) GNUNET_MQ_extract_nested_mh (req);
503 LOG (GNUNET_ERROR_TYPE_DEBUG,
504 "Received join_msg of type %u and size %u.\n",
505 ntohs (join_msg->header.type),
506 ntohs (join_msg->header.size));
507 }
508
509 struct GNUNET_PSYC_JoinHandle *jh = GNUNET_malloc (sizeof (*jh));
510 jh->mst = mst;
511 jh->slave_pub_key = req->slave_pub_key;
512
513 if (NULL != mst->join_req_cb)
514 mst->join_req_cb (mst->cb_cls, req, &req->slave_pub_key, join_msg, jh);
515}
516
517
518static void
519handle_slave_join_ack (void *cls,
520 const struct GNUNET_PSYC_CountersResultMessage *cres)
521{
522 struct GNUNET_PSYC_Slave *slv = cls;
523
524 int32_t result = ntohl (cres->result_code);
525 if (GNUNET_YES != result && GNUNET_NO != result)
526 {
527 LOG (GNUNET_ERROR_TYPE_ERROR, "Could not join slave.\n");
528 GNUNET_break (0);
529 /* FIXME: disconnect */
530 }
531 if (NULL != slv->connect_cb)
532 slv->connect_cb (slv->cb_cls, result, GNUNET_ntohll (cres->max_message_id));
533}
534
535
536static int
537check_slave_join_decision (void *cls,
538 const struct GNUNET_PSYC_JoinDecisionMessage *dcsn)
539{
540 return GNUNET_OK;
541}
542
543
544static void
545handle_slave_join_decision (void *cls,
546 const struct GNUNET_PSYC_JoinDecisionMessage *dcsn)
547{
548 struct GNUNET_PSYC_Slave *slv = cls;
549
550 struct GNUNET_PSYC_Message *pmsg = NULL;
551 if (ntohs (dcsn->header.size) <= sizeof (*dcsn) + sizeof (*pmsg))
552 pmsg = (struct GNUNET_PSYC_Message *) &dcsn[1];
553
554 if (NULL != slv->join_dcsn_cb)
555 slv->join_dcsn_cb (slv->cb_cls, dcsn, ntohl (dcsn->is_admitted), pmsg);
556}
557
558
559static void
560channel_cleanup (struct GNUNET_PSYC_Channel *chn)
561{
562 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
563 "cleaning up channel %p\n",
564 chn);
565 if (NULL != chn->tmit)
566 {
567 GNUNET_PSYC_transmit_destroy (chn->tmit);
568 chn->tmit = NULL;
569 }
570 if (NULL != chn->recv)
571 {
572
573 GNUNET_PSYC_receive_destroy (chn->recv);
574 chn->recv = NULL;
575 }
576 if (NULL != chn->connect_env)
577 {
578 GNUNET_MQ_discard (chn->connect_env);
579 chn->connect_env = NULL;
580 }
581 if (NULL != chn->mq)
582 {
583 GNUNET_MQ_destroy (chn->mq);
584 chn->mq = NULL;
585 }
586 if (NULL != chn->disconnect_cb)
587 {
588 chn->disconnect_cb (chn->disconnect_cls);
589 chn->disconnect_cb = NULL;
590 }
591 GNUNET_free (chn);
592}
593
594
595static void
596handle_channel_part_ack (void *cls,
597 const struct GNUNET_MessageHeader *msg)
598{
599 struct GNUNET_PSYC_Channel *chn = cls;
600
601 channel_cleanup (chn);
602}
603
604
605/*** MASTER ***/
606
607
608static void
609master_connect (struct GNUNET_PSYC_Master *mst);
610
611
612static void
613master_reconnect (void *cls)
614{
615 master_connect (cls);
616}
617
618
619/**
620 * Master client disconnected from service.
621 *
622 * Reconnect after backoff period.
623 */
624static void
625master_disconnected (void *cls, enum GNUNET_MQ_Error error)
626{
627 struct GNUNET_PSYC_Master *mst = cls;
628 struct GNUNET_PSYC_Channel *chn = &mst->chn;
629
630 LOG (GNUNET_ERROR_TYPE_DEBUG,
631 "Master client disconnected (%d), re-connecting\n",
632 (int) error);
633 if (NULL != chn->tmit)
634 {
635 GNUNET_PSYC_transmit_destroy (chn->tmit);
636 chn->tmit = NULL;
637 }
638 if (NULL != chn->mq)
639 {
640 GNUNET_MQ_destroy (chn->mq);
641 chn->mq = NULL;
642 }
643 chn->reconnect_task = GNUNET_SCHEDULER_add_delayed (chn->reconnect_delay,
644 master_reconnect,
645 mst);
646 chn->reconnect_delay = GNUNET_TIME_STD_BACKOFF (chn->reconnect_delay);
647}
648
649
650static void
651master_connect (struct GNUNET_PSYC_Master *mst)
652{
653 struct GNUNET_PSYC_Channel *chn = &mst->chn;
654
655 struct GNUNET_MQ_MessageHandler handlers[] = {
656 GNUNET_MQ_hd_fixed_size (master_start_ack,
657 GNUNET_MESSAGE_TYPE_PSYC_MASTER_START_ACK,
658 struct GNUNET_PSYC_CountersResultMessage,
659 mst),
660 GNUNET_MQ_hd_var_size (master_join_request,
661 GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST,
662 struct GNUNET_PSYC_JoinRequestMessage,
663 mst),
664 GNUNET_MQ_hd_fixed_size (channel_part_ack,
665 GNUNET_MESSAGE_TYPE_PSYC_PART_ACK,
666 struct GNUNET_MessageHeader,
667 chn),
668 GNUNET_MQ_hd_var_size (channel_message,
669 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE,
670 struct GNUNET_PSYC_MessageHeader,
671 chn),
672 GNUNET_MQ_hd_fixed_size (channel_message_ack,
673 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK,
674 struct GNUNET_MessageHeader,
675 chn),
676 GNUNET_MQ_hd_var_size (channel_history_result,
677 GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT,
678 struct GNUNET_OperationResultMessage,
679 chn),
680 GNUNET_MQ_hd_var_size (channel_state_result,
681 GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT,
682 struct GNUNET_OperationResultMessage,
683 chn),
684 GNUNET_MQ_hd_var_size (channel_result,
685 GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE,
686 struct GNUNET_OperationResultMessage,
687 chn),
688 GNUNET_MQ_handler_end ()
689 };
690
691 chn->mq = GNUNET_CLIENT_connect (chn->cfg,
692 "psyc",
693 handlers,
694 &master_disconnected,
695 mst);
696 GNUNET_assert (NULL != chn->mq);
697 chn->tmit = GNUNET_PSYC_transmit_create (chn->mq);
698
699 GNUNET_MQ_send_copy (chn->mq, chn->connect_env);
700}
701
702
703/**
704 * Start a PSYC master channel.
705 *
706 * Will start a multicast group identified by the given ECC key. Messages
707 * received from group members will be given to the respective handler methods.
708 * If a new member wants to join a group, the "join" method handler will be
709 * invoked; the join handler must then generate a "join" message to approve the
710 * joining of the new member. The channel can also change group membership
711 * without explicit requests. Note that PSYC doesn't itself "understand" join
712 * or part messages, the respective methods must call other PSYC functions to
713 * inform PSYC about the meaning of the respective events.
714 *
715 * @param cfg Configuration to use (to connect to PSYC service).
716 * @param channel_key ECC key that will be used to sign messages for this
717 * PSYC session. The public key is used to identify the PSYC channel.
718 * Note that end-users will usually not use the private key directly, but
719 * rather look it up in GNS for places managed by other users, or select
720 * a file with the private key(s) when setting up their own channels
721 * FIXME: we'll likely want to use NOT the p521 curve here, but a cheaper
722 * one in the future.
723 * @param policy Channel policy specifying join and history restrictions.
724 * Used to automate join decisions.
725 * @param message_cb Function to invoke on message parts received from slaves.
726 * @param join_request_cb Function to invoke when a slave wants to join.
727 * @param master_start_cb Function to invoke after the channel master started.
728 * @param cls Closure for @a method and @a join_cb.
729 *
730 * @return Handle for the channel master, NULL on error.
731 */
732struct GNUNET_PSYC_Master *
733GNUNET_PSYC_master_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
734 const struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key,
735 enum GNUNET_PSYC_Policy policy,
736 GNUNET_PSYC_MasterStartCallback start_cb,
737 GNUNET_PSYC_JoinRequestCallback join_request_cb,
738 GNUNET_PSYC_MessageCallback message_cb,
739 GNUNET_PSYC_MessagePartCallback message_part_cb,
740 void *cls)
741{
742 struct GNUNET_PSYC_Master *mst = GNUNET_new (struct GNUNET_PSYC_Master);
743 struct GNUNET_PSYC_Channel *chn = &mst->chn;
744 struct MasterStartRequest *req;
745
746 chn->connect_env = GNUNET_MQ_msg (req,
747 GNUNET_MESSAGE_TYPE_PSYC_MASTER_START);
748 req->channel_key = *channel_key;
749 req->policy = policy;
750
751 chn->cfg = cfg;
752 chn->is_master = GNUNET_YES;
753 chn->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
754
755 chn->op = GNUNET_OP_create ();
756 chn->recv = GNUNET_PSYC_receive_create (message_cb, message_part_cb, cls);
757
758 mst->start_cb = start_cb;
759 mst->join_req_cb = join_request_cb;
760 mst->cb_cls = cls;
761
762 master_connect (mst);
763 return mst;
764}
765
766
767/**
768 * Stop a PSYC master channel.
769 *
770 * @param master PSYC channel master to stop.
771 * @param keep_active FIXME
772 */
773void
774GNUNET_PSYC_master_stop (struct GNUNET_PSYC_Master *mst,
775 int keep_active,
776 GNUNET_ContinuationCallback stop_cb,
777 void *stop_cls)
778{
779 struct GNUNET_PSYC_Channel *chn = &mst->chn;
780 struct GNUNET_MQ_Envelope *env;
781
782 chn->is_disconnecting = GNUNET_YES;
783 chn->disconnect_cb = stop_cb;
784 chn->disconnect_cls = stop_cls;
785 env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_PSYC_PART_REQUEST);
786 GNUNET_MQ_send (chn->mq, env);
787}
788
789
790/**
791 * Function to call with the decision made for a join request.
792 *
793 * Must be called once and only once in response to an invocation of the
794 * #GNUNET_PSYC_JoinCallback.
795 *
796 * @param jh Join request handle.
797 * @param is_admitted #GNUNET_YES if the join is approved,
798 * #GNUNET_NO if it is disapproved,
799 * #GNUNET_SYSERR if we cannot answer the request.
800 * @param relay_count Number of relays given.
801 * @param relays Array of suggested peers that might be useful relays to use
802 * when joining the multicast group (essentially a list of peers that
803 * are already part of the multicast group and might thus be willing
804 * to help with routing). If empty, only this local peer (which must
805 * be the multicast origin) is a good candidate for building the
806 * multicast tree. Note that it is unnecessary to specify our own
807 * peer identity in this array.
808 * @param join_resp Application-dependent join response message.
809 *
810 * @return #GNUNET_OK on success,
811 * #GNUNET_SYSERR if the message is too large.
812 */
813int
814GNUNET_PSYC_join_decision (struct GNUNET_PSYC_JoinHandle *jh,
815 int is_admitted,
816 uint32_t relay_count,
817 const struct GNUNET_PeerIdentity *relays,
818 const struct GNUNET_PSYC_Message *join_resp)
819{
820 struct GNUNET_PSYC_Channel *chn = &jh->mst->chn;
821 struct GNUNET_PSYC_JoinDecisionMessage *dcsn;
822 uint16_t join_resp_size
823 = (NULL != join_resp) ? ntohs (join_resp->header.size) : 0;
824 uint16_t relay_size = relay_count * sizeof (*relays);
825
826 if (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD
827 < sizeof (*dcsn) + relay_size + join_resp_size)
828 return GNUNET_SYSERR;
829
830 struct GNUNET_MQ_Envelope *
831 env = GNUNET_MQ_msg_extra (dcsn, relay_size + join_resp_size,
832 GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION);
833 dcsn->is_admitted = htonl (is_admitted);
834 dcsn->slave_pub_key = jh->slave_pub_key;
835
836 if (0 < join_resp_size)
837 GNUNET_memcpy (&dcsn[1], join_resp, join_resp_size);
838
839 GNUNET_MQ_send (chn->mq, env);
840 GNUNET_free (jh);
841 return GNUNET_OK;
842}
843
844
845/**
846 * Send a message to call a method to all members in the PSYC channel.
847 *
848 * @param master Handle to the PSYC channel.
849 * @param method_name Which method should be invoked.
850 * @param notify_mod Function to call to obtain modifiers.
851 * @param notify_data Function to call to obtain fragments of the data.
852 * @param notify_cls Closure for @a notify_mod and @a notify_data.
853 * @param flags Flags for the message being transmitted.
854 *
855 * @return Transmission handle, NULL on error (i.e. more than one request queued).
856 */
857struct GNUNET_PSYC_MasterTransmitHandle *
858GNUNET_PSYC_master_transmit (struct GNUNET_PSYC_Master *mst,
859 const char *method_name,
860 GNUNET_PSYC_TransmitNotifyModifier notify_mod,
861 GNUNET_PSYC_TransmitNotifyData notify_data,
862 void *notify_cls,
863 enum GNUNET_PSYC_MasterTransmitFlags flags)
864{
865 if (GNUNET_OK
866 == GNUNET_PSYC_transmit_message (mst->chn.tmit, method_name, NULL,
867 notify_mod, notify_data, notify_cls,
868 flags))
869 return (struct GNUNET_PSYC_MasterTransmitHandle *) mst->chn.tmit;
870 else
871 return NULL;
872}
873
874
875/**
876 * Resume transmission to the channel.
877 *
878 * @param tmit Handle of the request that is being resumed.
879 */
880void
881GNUNET_PSYC_master_transmit_resume (struct GNUNET_PSYC_MasterTransmitHandle *tmit)
882{
883 GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) tmit);
884}
885
886
887/**
888 * Abort transmission request to the channel.
889 *
890 * @param tmit Handle of the request that is being aborted.
891 */
892void
893GNUNET_PSYC_master_transmit_cancel (struct GNUNET_PSYC_MasterTransmitHandle *tmit)
894{
895 GNUNET_PSYC_transmit_cancel ((struct GNUNET_PSYC_TransmitHandle *) tmit);
896}
897
898
899/**
900 * Convert a channel @a master to a @e channel handle to access the @e channel
901 * APIs.
902 *
903 * @param master Channel master handle.
904 *
905 * @return Channel handle, valid for as long as @a master is valid.
906 */
907struct GNUNET_PSYC_Channel *
908GNUNET_PSYC_master_get_channel (struct GNUNET_PSYC_Master *master)
909{
910 return &master->chn;
911}
912
913
914/*** SLAVE ***/
915
916
917static void
918slave_connect (struct GNUNET_PSYC_Slave *slv);
919
920
921static void
922slave_reconnect (void *cls)
923{
924 slave_connect (cls);
925}
926
927
928/**
929 * Slave client disconnected from service.
930 *
931 * Reconnect after backoff period.
932 */
933static void
934slave_disconnected (void *cls,
935 enum GNUNET_MQ_Error error)
936{
937 struct GNUNET_PSYC_Slave *slv = cls;
938 struct GNUNET_PSYC_Channel *chn = &slv->chn;
939
940 LOG (GNUNET_ERROR_TYPE_DEBUG,
941 "Slave client disconnected (%d), re-connecting\n",
942 (int) error);
943 if (NULL != chn->tmit)
944 {
945 GNUNET_PSYC_transmit_destroy (chn->tmit);
946 chn->tmit = NULL;
947 }
948 if (NULL != chn->mq)
949 {
950 GNUNET_MQ_destroy (chn->mq);
951 chn->mq = NULL;
952 }
953 chn->reconnect_task = GNUNET_SCHEDULER_add_delayed (chn->reconnect_delay,
954 &slave_reconnect,
955 slv);
956 chn->reconnect_delay = GNUNET_TIME_STD_BACKOFF (chn->reconnect_delay);
957}
958
959
960static void
961slave_connect (struct GNUNET_PSYC_Slave *slv)
962{
963 struct GNUNET_PSYC_Channel *chn = &slv->chn;
964
965 struct GNUNET_MQ_MessageHandler handlers[] = {
966 GNUNET_MQ_hd_fixed_size (slave_join_ack,
967 GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN_ACK,
968 struct GNUNET_PSYC_CountersResultMessage,
969 slv),
970 GNUNET_MQ_hd_var_size (slave_join_decision,
971 GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION,
972 struct GNUNET_PSYC_JoinDecisionMessage,
973 slv),
974 GNUNET_MQ_hd_fixed_size (channel_part_ack,
975 GNUNET_MESSAGE_TYPE_PSYC_PART_ACK,
976 struct GNUNET_MessageHeader,
977 chn),
978 GNUNET_MQ_hd_var_size (channel_message,
979 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE,
980 struct GNUNET_PSYC_MessageHeader,
981 chn),
982 GNUNET_MQ_hd_fixed_size (channel_message_ack,
983 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK,
984 struct GNUNET_MessageHeader,
985 chn),
986 GNUNET_MQ_hd_var_size (channel_history_result,
987 GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT,
988 struct GNUNET_OperationResultMessage,
989 chn),
990 GNUNET_MQ_hd_var_size (channel_state_result,
991 GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT,
992 struct GNUNET_OperationResultMessage,
993 chn),
994 GNUNET_MQ_hd_var_size (channel_result,
995 GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE,
996 struct GNUNET_OperationResultMessage,
997 chn),
998 GNUNET_MQ_handler_end ()
999 };
1000
1001 chn->mq = GNUNET_CLIENT_connect (chn->cfg,
1002 "psyc",
1003 handlers,
1004 &slave_disconnected,
1005 slv);
1006 if (NULL == chn->mq)
1007 {
1008 chn->reconnect_task = GNUNET_SCHEDULER_add_delayed (chn->reconnect_delay,
1009 &slave_reconnect,
1010 slv);
1011 chn->reconnect_delay = GNUNET_TIME_STD_BACKOFF (chn->reconnect_delay);
1012 return;
1013 }
1014 chn->tmit = GNUNET_PSYC_transmit_create (chn->mq);
1015
1016 GNUNET_MQ_send_copy (chn->mq, chn->connect_env);
1017}
1018
1019
1020/**
1021 * Join a PSYC channel.
1022 *
1023 * The entity joining is always the local peer. The user must immediately use
1024 * the GNUNET_PSYC_slave_transmit() functions to transmit a @e join_msg to the
1025 * channel; if the join request succeeds, the channel state (and @e recent
1026 * method calls) will be replayed to the joining member. There is no explicit
1027 * notification on failure (as the channel may simply take days to approve,
1028 * and disapproval is simply being ignored).
1029 *
1030 * @param cfg
1031 * Configuration to use.
1032 * @param channel_key ECC public key that identifies the channel we wish to join.
1033 * @param slave_key ECC private-public key pair that identifies the slave, and
1034 * used by multicast to sign the join request and subsequent unicast
1035 * requests sent to the master.
1036 * @param origin Peer identity of the origin.
1037 * @param relay_count Number of peers in the @a relays array.
1038 * @param relays Peer identities of members of the multicast group, which serve
1039 * as relays and used to join the group at.
1040 * @param message_cb Function to invoke on message parts received from the
1041 * channel, typically at least contains method handlers for @e join and
1042 * @e part.
1043 * @param slave_connect_cb Function invoked once we have connected to the
1044 * PSYC service.
1045 * @param join_decision_cb Function invoked once we have received a join
1046 * decision.
1047 * @param cls Closure for @a message_cb and @a slave_joined_cb.
1048 * @param method_name Method name for the join request.
1049 * @param env Environment containing transient variables for the request, or NULL.
1050 * @param data Payload for the join message.
1051 * @param data_size Number of bytes in @a data.
1052 *
1053 * @return Handle for the slave, NULL on error.
1054 */
1055struct GNUNET_PSYC_Slave *
1056GNUNET_PSYC_slave_join (const struct GNUNET_CONFIGURATION_Handle *cfg,
1057 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_pub_key,
1058 const struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key,
1059 enum GNUNET_PSYC_SlaveJoinFlags flags,
1060 const struct GNUNET_PeerIdentity *origin,
1061 uint32_t relay_count,
1062 const struct GNUNET_PeerIdentity *relays,
1063 GNUNET_PSYC_MessageCallback message_cb,
1064 GNUNET_PSYC_MessagePartCallback message_part_cb,
1065 GNUNET_PSYC_SlaveConnectCallback connect_cb,
1066 GNUNET_PSYC_JoinDecisionCallback join_decision_cb,
1067 void *cls,
1068 const struct GNUNET_PSYC_Message *join_msg)
1069{
1070 struct GNUNET_PSYC_Slave *slv = GNUNET_malloc (sizeof (*slv));
1071 struct GNUNET_PSYC_Channel *chn = &slv->chn;
1072 uint16_t relay_size = relay_count * sizeof (*relays);
1073 uint16_t join_msg_size;
1074 if (NULL == join_msg)
1075 join_msg_size = 0;
1076 else
1077 join_msg_size = ntohs (join_msg->header.size);
1078
1079 struct SlaveJoinRequest *req;
1080 chn->connect_env = GNUNET_MQ_msg_extra (req, relay_size + join_msg_size,
1081 GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN);
1082 req->channel_pub_key = *channel_pub_key;
1083 req->slave_key = *slave_key;
1084 req->origin = *origin;
1085 req->relay_count = htonl (relay_count);
1086 req->flags = htonl (flags);
1087
1088 if (0 < relay_size)
1089 GNUNET_memcpy (&req[1], relays, relay_size);
1090
1091 if (NULL != join_msg)
1092 GNUNET_memcpy ((char *) &req[1] + relay_size, join_msg, join_msg_size);
1093
1094 chn->cfg = cfg;
1095 chn->is_master = GNUNET_NO;
1096 chn->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
1097
1098 chn->op = GNUNET_OP_create ();
1099 chn->recv = GNUNET_PSYC_receive_create (message_cb, message_part_cb, cls);
1100
1101 slv->connect_cb = connect_cb;
1102 slv->join_dcsn_cb = join_decision_cb;
1103 slv->cb_cls = cls;
1104
1105 slave_connect (slv);
1106 return slv;
1107}
1108
1109
1110/**
1111 * Part a PSYC channel.
1112 *
1113 * Will terminate the connection to the PSYC service. Polite clients should
1114 * first explicitly send a part request (via GNUNET_PSYC_slave_transmit()).
1115 *
1116 * @param slave Slave handle.
1117 */
1118void
1119GNUNET_PSYC_slave_part (struct GNUNET_PSYC_Slave *slv,
1120 int keep_active,
1121 GNUNET_ContinuationCallback part_cb,
1122 void *part_cls)
1123{
1124 struct GNUNET_PSYC_Channel *chn = &slv->chn;
1125 struct GNUNET_MQ_Envelope *env;
1126
1127 chn->is_disconnecting = GNUNET_YES;
1128 chn->disconnect_cb = part_cb;
1129 chn->disconnect_cls = part_cls;
1130 env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_PSYC_PART_REQUEST);
1131 GNUNET_MQ_send (chn->mq, env);
1132}
1133
1134
1135/**
1136 * Request a message to be sent to the channel master.
1137 *
1138 * @param slave Slave handle.
1139 * @param method_name Which (PSYC) method should be invoked (on host).
1140 * @param notify_mod Function to call to obtain modifiers.
1141 * @param notify_data Function to call to obtain fragments of the data.
1142 * @param notify_cls Closure for @a notify.
1143 * @param flags Flags for the message being transmitted.
1144 *
1145 * @return Transmission handle, NULL on error (i.e. more than one request
1146 * queued).
1147 */
1148struct GNUNET_PSYC_SlaveTransmitHandle *
1149GNUNET_PSYC_slave_transmit (struct GNUNET_PSYC_Slave *slv,
1150 const char *method_name,
1151 GNUNET_PSYC_TransmitNotifyModifier notify_mod,
1152 GNUNET_PSYC_TransmitNotifyData notify_data,
1153 void *notify_cls,
1154 enum GNUNET_PSYC_SlaveTransmitFlags flags)
1155
1156{
1157 if (GNUNET_OK
1158 == GNUNET_PSYC_transmit_message (slv->chn.tmit, method_name, NULL,
1159 notify_mod, notify_data, notify_cls,
1160 flags))
1161 return (struct GNUNET_PSYC_SlaveTransmitHandle *) slv->chn.tmit;
1162 else
1163 return NULL;
1164}
1165
1166
1167/**
1168 * Resume transmission to the master.
1169 *
1170 * @param tmit Handle of the request that is being resumed.
1171 */
1172void
1173GNUNET_PSYC_slave_transmit_resume (struct GNUNET_PSYC_SlaveTransmitHandle *tmit)
1174{
1175 GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) tmit);
1176}
1177
1178
1179/**
1180 * Abort transmission request to master.
1181 *
1182 * @param tmit Handle of the request that is being aborted.
1183 */
1184void
1185GNUNET_PSYC_slave_transmit_cancel (struct GNUNET_PSYC_SlaveTransmitHandle *tmit)
1186{
1187 GNUNET_PSYC_transmit_cancel ((struct GNUNET_PSYC_TransmitHandle *) tmit);
1188}
1189
1190
1191/**
1192 * Convert @a slave to a @e channel handle to access the @e channel APIs.
1193 *
1194 * @param slv Slave handle.
1195 *
1196 * @return Channel handle, valid for as long as @a slave is valid.
1197 */
1198struct GNUNET_PSYC_Channel *
1199GNUNET_PSYC_slave_get_channel (struct GNUNET_PSYC_Slave *slv)
1200{
1201 return &slv->chn;
1202}
1203
1204
1205/**
1206 * Add a slave to the channel's membership list.
1207 *
1208 * Note that this will NOT generate any PSYC traffic, it will merely update the
1209 * local database to modify how we react to <em>membership test</em> queries.
1210 * The channel master still needs to explicitly transmit a @e join message to
1211 * notify other channel members and they then also must still call this function
1212 * in their respective methods handling the @e join message. This way, how @e
1213 * join and @e part operations are exactly implemented is still up to the
1214 * application; for example, there might be a @e part_all method to kick out
1215 * everyone.
1216 *
1217 * Note that channel slaves are explicitly trusted to execute such methods
1218 * correctly; not doing so correctly will result in either denying other slaves
1219 * access or offering access to channel data to non-members.
1220 *
1221 * @param chn
1222 * Channel handle.
1223 * @param slave_pub_key
1224 * Identity of channel slave to add.
1225 * @param announced_at
1226 * ID of the message that announced the membership change.
1227 * @param effective_since
1228 * Addition of slave is in effect since this message ID.
1229 * @param result_cb
1230 * Function to call with the result of the operation.
1231 * The @e result_code argument is #GNUNET_OK on success, or
1232 * #GNUNET_SYSERR on error. In case of an error, the @e data argument
1233 * can contain an optional error message.
1234 * @param cls
1235 * Closure for @a result_cb.
1236 */
1237void
1238GNUNET_PSYC_channel_slave_add (struct GNUNET_PSYC_Channel *chn,
1239 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key,
1240 uint64_t announced_at,
1241 uint64_t effective_since,
1242 GNUNET_ResultCallback result_cb,
1243 void *cls)
1244{
1245 struct ChannelMembershipStoreRequest *req;
1246 struct GNUNET_MQ_Envelope *
1247 env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_MEMBERSHIP_STORE);
1248 req->slave_pub_key = *slave_pub_key;
1249 req->announced_at = GNUNET_htonll (announced_at);
1250 req->effective_since = GNUNET_htonll (effective_since);
1251 req->did_join = GNUNET_YES;
1252 req->op_id = GNUNET_htonll (GNUNET_OP_add (chn->op, result_cb, cls, NULL));
1253
1254 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1255 "GNUNET_PSYC_channel_slave_add, OP ID: %" PRIu64 "\n",
1256 GNUNET_ntohll (req->op_id));
1257 GNUNET_MQ_send (chn->mq, env);
1258}
1259
1260
1261/**
1262 * Remove a slave from the channel's membership list.
1263 *
1264 * Note that this will NOT generate any PSYC traffic, it will merely update the
1265 * local database to modify how we react to <em>membership test</em> queries.
1266 * The channel master still needs to explicitly transmit a @e part message to
1267 * notify other channel members and they then also must still call this function
1268 * in their respective methods handling the @e part message. This way, how
1269 * @e join and @e part operations are exactly implemented is still up to the
1270 * application; for example, there might be a @e part_all message to kick out
1271 * everyone.
1272 *
1273 * Note that channel members are explicitly trusted to perform these
1274 * operations correctly; not doing so correctly will result in either
1275 * denying members access or offering access to channel data to
1276 * non-members.
1277 *
1278 * @param chn
1279 * Channel handle.
1280 * @param slave_pub_key
1281 * Identity of channel slave to remove.
1282 * @param announced_at
1283 * ID of the message that announced the membership change.
1284 * @param result_cb
1285 * Function to call with the result of the operation.
1286 * The @e result_code argument is #GNUNET_OK on success, or
1287 * #GNUNET_SYSERR on error. In case of an error, the @e data argument
1288 * can contain an optional error message.
1289 * @param cls
1290 * Closure for @a result_cb.
1291 */
1292void
1293GNUNET_PSYC_channel_slave_remove (struct GNUNET_PSYC_Channel *chn,
1294 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key,
1295 uint64_t announced_at,
1296 GNUNET_ResultCallback result_cb,
1297 void *cls)
1298{
1299 struct ChannelMembershipStoreRequest *req;
1300 struct GNUNET_MQ_Envelope *
1301 env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_MEMBERSHIP_STORE);
1302 req->slave_pub_key = *slave_pub_key;
1303 req->announced_at = GNUNET_htonll (announced_at);
1304 req->did_join = GNUNET_NO;
1305 req->op_id = GNUNET_htonll (GNUNET_OP_add (chn->op, result_cb, cls, NULL));
1306
1307 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1308 "GNUNET_PSYC_channel_slave_remove, OP ID: %" PRIu64 "\n",
1309 GNUNET_ntohll (req->op_id));
1310 GNUNET_MQ_send (chn->mq, env);
1311}
1312
1313
1314static struct GNUNET_PSYC_HistoryRequest *
1315channel_history_replay (struct GNUNET_PSYC_Channel *chn,
1316 uint64_t start_message_id,
1317 uint64_t end_message_id,
1318 uint64_t message_limit,
1319 const char *method_prefix,
1320 uint32_t flags,
1321 GNUNET_PSYC_MessageCallback message_cb,
1322 GNUNET_PSYC_MessagePartCallback message_part_cb,
1323 GNUNET_ResultCallback result_cb,
1324 void *cls)
1325{
1326 struct GNUNET_PSYC_HistoryRequestMessage *req;
1327 struct GNUNET_PSYC_HistoryRequest *hist = GNUNET_malloc (sizeof (*hist));
1328 hist->chn = chn;
1329 hist->recv = GNUNET_PSYC_receive_create (message_cb, message_part_cb, cls);
1330 hist->result_cb = result_cb;
1331 hist->cls = cls;
1332 hist->op_id = GNUNET_OP_add (chn->op, op_recv_history_result, hist, NULL);
1333
1334 GNUNET_assert (NULL != method_prefix);
1335 uint16_t method_size = strnlen (method_prefix,
1336 GNUNET_MAX_MESSAGE_SIZE
1337 - sizeof (*req)) + 1;
1338 GNUNET_assert ('\0' == method_prefix[method_size - 1]);
1339
1340 struct GNUNET_MQ_Envelope *
1341 env = GNUNET_MQ_msg_extra (req, method_size,
1342 GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY);
1343 req->start_message_id = GNUNET_htonll (start_message_id);
1344 req->end_message_id = GNUNET_htonll (end_message_id);
1345 req->message_limit = GNUNET_htonll (message_limit);
1346 req->flags = htonl (flags);
1347 req->op_id = GNUNET_htonll (hist->op_id);
1348
1349 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1350 "channel_history_replay, OP ID: %" PRIu64 "\n",
1351 GNUNET_ntohll (req->op_id));
1352 GNUNET_memcpy (&req[1], method_prefix, method_size);
1353
1354 GNUNET_MQ_send (chn->mq, env);
1355 return hist;
1356}
1357
1358
1359/**
1360 * Request to replay a part of the message history of the channel.
1361 *
1362 * Historic messages (but NOT the state at the time) will be replayed and given
1363 * to the normal method handlers with a #GNUNET_PSYC_MESSAGE_HISTORIC flag set.
1364 *
1365 * Messages are retrieved from the local PSYCstore if available,
1366 * otherwise requested from the network.
1367 *
1368 * @param channel
1369 * Which channel should be replayed?
1370 * @param start_message_id
1371 * Earliest interesting point in history.
1372 * @param end_message_id
1373 * Last (inclusive) interesting point in history.
1374 * @param method_prefix
1375 * Retrieve only messages with a matching method prefix.
1376 * @param flags
1377 * OR'ed enum GNUNET_PSYC_HistoryReplayFlags
1378 * @param result_cb
1379 * Function to call when the requested history has been fully replayed.
1380 * @param cls
1381 * Closure for the callbacks.
1382 *
1383 * @return Handle to cancel history replay operation.
1384 */
1385struct GNUNET_PSYC_HistoryRequest *
1386GNUNET_PSYC_channel_history_replay (struct GNUNET_PSYC_Channel *chn,
1387 uint64_t start_message_id,
1388 uint64_t end_message_id,
1389 const char *method_prefix,
1390 uint32_t flags,
1391 GNUNET_PSYC_MessageCallback message_cb,
1392 GNUNET_PSYC_MessagePartCallback message_part_cb,
1393 GNUNET_ResultCallback result_cb,
1394 void *cls)
1395{
1396 return channel_history_replay (chn, start_message_id, end_message_id, 0,
1397 method_prefix, flags,
1398 message_cb, message_part_cb, result_cb, cls);
1399}
1400
1401
1402/**
1403 * Request to replay the latest messages from the message history of the channel.
1404 *
1405 * Historic messages (but NOT the state at the time) will be replayed (given to
1406 * the normal method handlers) if available and if access is permitted.
1407 *
1408 * @param channel
1409 * Which channel should be replayed?
1410 * @param message_limit
1411 * Maximum number of messages to replay.
1412 * @param method_prefix
1413 * Retrieve only messages with a matching method prefix.
1414 * Use NULL or "" to retrieve all.
1415 * @param flags
1416 * OR'ed enum GNUNET_PSYC_HistoryReplayFlags
1417 * @param result_cb
1418 * Function to call when the requested history has been fully replayed.
1419 * @param cls
1420 * Closure for the callbacks.
1421 *
1422 * @return Handle to cancel history replay operation.
1423 */
1424struct GNUNET_PSYC_HistoryRequest *
1425GNUNET_PSYC_channel_history_replay_latest (struct GNUNET_PSYC_Channel *chn,
1426 uint64_t message_limit,
1427 const char *method_prefix,
1428 uint32_t flags,
1429 GNUNET_PSYC_MessageCallback message_cb,
1430 GNUNET_PSYC_MessagePartCallback message_part_cb,
1431 GNUNET_ResultCallback result_cb,
1432 void *cls)
1433{
1434 return channel_history_replay (chn, 0, 0, message_limit, method_prefix, flags,
1435 message_cb, message_part_cb, result_cb, cls);
1436}
1437
1438
1439void
1440GNUNET_PSYC_channel_history_replay_cancel (struct GNUNET_PSYC_Channel *channel,
1441 struct GNUNET_PSYC_HistoryRequest *hist)
1442{
1443 GNUNET_PSYC_receive_destroy (hist->recv);
1444 GNUNET_OP_remove (hist->chn->op, hist->op_id);
1445 GNUNET_free (hist);
1446}
1447
1448
1449/**
1450 * Retrieve the best matching channel state variable.
1451 *
1452 * If the requested variable name is not present in the state, the nearest
1453 * less-specific name is matched; for example, requesting "_a_b" will match "_a"
1454 * if "_a_b" does not exist.
1455 *
1456 * @param channel
1457 * Channel handle.
1458 * @param full_name
1459 * Full name of the requested variable.
1460 * The actual variable returned might have a shorter name.
1461 * @param var_cb
1462 * Function called once when a matching state variable is found.
1463 * Not called if there's no matching state variable.
1464 * @param result_cb
1465 * Function called after the operation finished.
1466 * (i.e. all state variables have been returned via @a state_cb)
1467 * @param cls
1468 * Closure for the callbacks.
1469 */
1470static struct GNUNET_PSYC_StateRequest *
1471channel_state_get (struct GNUNET_PSYC_Channel *chn,
1472 uint16_t type, const char *name,
1473 GNUNET_PSYC_StateVarCallback var_cb,
1474 GNUNET_ResultCallback result_cb, void *cls)
1475{
1476 struct StateRequest *req;
1477 struct GNUNET_PSYC_StateRequest *sr = GNUNET_malloc (sizeof (*sr));
1478 sr->chn = chn;
1479 sr->var_cb = var_cb;
1480 sr->result_cb = result_cb;
1481 sr->cls = cls;
1482 sr->op_id = GNUNET_OP_add (chn->op, op_recv_state_result, sr, NULL);
1483
1484 GNUNET_assert (NULL != name);
1485 size_t name_size = strnlen (name, GNUNET_MAX_MESSAGE_SIZE
1486 - sizeof (*req)) + 1;
1487 struct GNUNET_MQ_Envelope *
1488 env = GNUNET_MQ_msg_extra (req, name_size, type);
1489 req->op_id = GNUNET_htonll (sr->op_id);
1490
1491 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1492 "channel_state_get, OP ID: %" PRIu64 "\n",
1493 GNUNET_ntohll (req->op_id));
1494
1495 GNUNET_memcpy (&req[1], name, name_size);
1496
1497 GNUNET_MQ_send (chn->mq, env);
1498 return sr;
1499}
1500
1501
1502/**
1503 * Retrieve the best matching channel state variable.
1504 *
1505 * If the requested variable name is not present in the state, the nearest
1506 * less-specific name is matched; for example, requesting "_a_b" will match "_a"
1507 * if "_a_b" does not exist.
1508 *
1509 * @param channel
1510 * Channel handle.
1511 * @param full_name
1512 * Full name of the requested variable.
1513 * The actual variable returned might have a shorter name.
1514 * @param var_cb
1515 * Function called once when a matching state variable is found.
1516 * Not called if there's no matching state variable.
1517 * @param result_cb
1518 * Function called after the operation finished.
1519 * (i.e. all state variables have been returned via @a state_cb)
1520 * @param cls
1521 * Closure for the callbacks.
1522 */
1523struct GNUNET_PSYC_StateRequest *
1524GNUNET_PSYC_channel_state_get (struct GNUNET_PSYC_Channel *chn,
1525 const char *full_name,
1526 GNUNET_PSYC_StateVarCallback var_cb,
1527 GNUNET_ResultCallback result_cb,
1528 void *cls)
1529{
1530 return channel_state_get (chn, GNUNET_MESSAGE_TYPE_PSYC_STATE_GET,
1531 full_name, var_cb, result_cb, cls);
1532
1533}
1534
1535
1536/**
1537 * Return all channel state variables whose name matches a given prefix.
1538 *
1539 * A name matches if it starts with the given @a name_prefix, thus requesting
1540 * the empty prefix ("") will match all values; requesting "_a_b" will also
1541 * return values stored under "_a_b_c".
1542 *
1543 * The @a state_cb is invoked on all matching state variables asynchronously, as
1544 * the state is stored in and retrieved from the PSYCstore,
1545 *
1546 * @param channel
1547 * Channel handle.
1548 * @param name_prefix
1549 * Prefix of the state variable name to match.
1550 * @param var_cb
1551 * Function called once when a matching state variable is found.
1552 * Not called if there's no matching state variable.
1553 * @param result_cb
1554 * Function called after the operation finished.
1555 * (i.e. all state variables have been returned via @a state_cb)
1556 * @param cls
1557 * Closure for the callbacks.
1558 */
1559struct GNUNET_PSYC_StateRequest *
1560GNUNET_PSYC_channel_state_get_prefix (struct GNUNET_PSYC_Channel *chn,
1561 const char *name_prefix,
1562 GNUNET_PSYC_StateVarCallback var_cb,
1563 GNUNET_ResultCallback result_cb,
1564 void *cls)
1565{
1566 return channel_state_get (chn, GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX,
1567 name_prefix, var_cb, result_cb, cls);
1568}
1569
1570
1571/**
1572 * Cancel a state request operation.
1573 *
1574 * @param sr
1575 * Handle for the operation to cancel.
1576 */
1577void
1578GNUNET_PSYC_channel_state_get_cancel (struct GNUNET_PSYC_StateRequest *sr)
1579{
1580 GNUNET_OP_remove (sr->chn->op, sr->op_id);
1581 GNUNET_free (sr);
1582}
1583
1584/* 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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file psyc/test_psyc_api_join.c
23 * @brief library for writing psyc tests
24 * @author xrs
25 */
26
27#define MAX_TESTBED_OPS 32
28
29struct pctx
30{
31 int idx;
32
33 struct GNUNET_TESTBED_Peer *testbed_peer;
34
35 const struct GNUNET_PeerIdentity *peer_id;
36
37 const struct GNUNET_PeerIdentity *peer_id_master;
38
39 /**
40 * Used to simulate egos (not peerid)
41 */
42 const struct GNUNET_CRYPTO_EcdsaPrivateKey *id_key;
43
44 const struct GNUNET_CRYPTO_EcdsaPublicKey *id_pub_key;
45
46 /**
47 * Used to store either GNUNET_PSYC_Master or GNUNET_PSYC_Slave handle
48 */
49 void *psyc;
50
51 struct GNUNET_PSYC_Channel *channel;
52
53 const struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key;
54
55 struct GNUNET_CRYPTO_EddsaPublicKey *channel_pub_key;
56
57 int test_ok;
58};
59
60static struct GNUNET_SCHEDULER_Task *timeout_task_id;
61
62static int result = GNUNET_SYSERR;
63
64static struct GNUNET_TESTBED_Operation *op[MAX_TESTBED_OPS];
65
66static int op_cnt = 0;
67
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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file psyc/test_psyc.c
23 * @brief Tests for the PSYC API.
24 * @author Gabor X Toth
25 * @author Christian Grothoff
26 */
27
28#include <inttypes.h>
29
30#include "platform.h"
31#include "gnunet_crypto_lib.h"
32#include "gnunet_common.h"
33#include "gnunet_util_lib.h"
34#include "gnunet_testing_lib.h"
35#include "gnunet_psyc_util_lib.h"
36#include "gnunet_psyc_service.h"
37
38#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
39
40/**
41 * Return value from 'main'.
42 */
43static int res;
44
45static const struct GNUNET_CONFIGURATION_Handle *cfg;
46
47static struct GNUNET_PeerIdentity this_peer;
48
49/**
50 * Handle for task for timeout termination.
51 */
52static struct GNUNET_SCHEDULER_Task * end_badly_task;
53
54static struct GNUNET_PSYC_Master *mst;
55static struct GNUNET_PSYC_Slave *slv;
56
57static struct GNUNET_PSYC_Channel *mst_chn, *slv_chn;
58
59static struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key;
60static struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key;
61
62static struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key;
63static struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key;
64
65struct TransmitClosure
66{
67 struct GNUNET_PSYC_MasterTransmitHandle *mst_tmit;
68 struct GNUNET_PSYC_SlaveTransmitHandle *slv_tmit;
69 struct GNUNET_PSYC_Environment *env;
70 struct GNUNET_PSYC_Modifier *mod;
71 char *data[16];
72 const char *mod_value;
73 size_t mod_value_size;
74 uint8_t data_delay[16];
75 uint8_t data_count;
76 uint8_t paused;
77 uint8_t n;
78};
79
80static struct TransmitClosure *tmit;
81
82static uint8_t join_req_count, end_count;
83
84enum
85{
86 TEST_NONE = 0,
87 TEST_MASTER_START = 1,
88 TEST_SLAVE_JOIN_REJECT = 2,
89 TEST_SLAVE_JOIN_ACCEPT = 3,
90 TEST_SLAVE_ADD = 4,
91 TEST_SLAVE_REMOVE = 5,
92 TEST_SLAVE_TRANSMIT = 6,
93 TEST_MASTER_TRANSMIT = 7,
94 TEST_MASTER_HISTORY_REPLAY_LATEST = 8,
95 TEST_SLAVE_HISTORY_REPLAY_LATEST = 9,
96 TEST_MASTER_HISTORY_REPLAY = 10,
97 TEST_SLAVE_HISTORY_REPLAY = 11,
98 TEST_MASTER_STATE_GET = 12,
99 TEST_SLAVE_STATE_GET = 13,
100 TEST_MASTER_STATE_GET_PREFIX = 14,
101 TEST_SLAVE_STATE_GET_PREFIX = 15,
102} test;
103
104
105static void
106master_transmit ();
107
108static void
109master_history_replay_latest ();
110
111
112static void
113master_stopped (void *cls)
114{
115 if (NULL != tmit)
116 {
117 GNUNET_PSYC_env_destroy (tmit->env);
118 GNUNET_free (tmit);
119 tmit = NULL;
120 }
121 GNUNET_SCHEDULER_shutdown ();
122}
123
124
125static void
126slave_parted (void *cls)
127{
128 if (NULL != mst)
129 {
130 GNUNET_PSYC_master_stop (mst, GNUNET_NO, &master_stopped, NULL);
131 mst = NULL;
132 }
133 else
134 master_stopped (NULL);
135}
136
137
138/**
139 * Clean up all resources used.
140 */
141static void
142cleanup ()
143{
144 if (NULL != slv)
145 {
146 GNUNET_PSYC_slave_part (slv, GNUNET_NO, &slave_parted, NULL);
147 slv = NULL;
148 }
149 else
150 slave_parted (NULL);
151}
152
153
154/**
155 * Terminate the test case (failure).
156 *
157 * @param cls NULL
158 */
159static void
160end_badly (void *cls)
161{
162 res = 1;
163 cleanup ();
164 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test FAILED.\n");
165}
166
167
168/**
169 * Terminate the test case (success).
170 *
171 * @param cls NULL
172 */
173static void
174end_normally (void *cls)
175{
176 res = 0;
177 cleanup ();
178 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Test PASSED.\n");
179}
180
181
182/**
183 * Finish the test case (successfully).
184 */
185static void
186end ()
187{
188 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Ending tests.\n");
189
190 if (end_badly_task != NULL)
191 {
192 GNUNET_SCHEDULER_cancel (end_badly_task);
193 end_badly_task = NULL;
194 }
195 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
196 &end_normally, NULL);
197}
198
199
200static void
201master_message_cb (void *cls, const struct GNUNET_PSYC_MessageHeader *msg)
202{
203 GNUNET_assert (NULL != msg);
204 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
205 "Test #%d: Master got PSYC message fragment of size %u "
206 "belonging to message ID %" PRIu64 " with flags %x\n",
207 test, ntohs (msg->header.size),
208 GNUNET_ntohll (msg->message_id), ntohl (msg->flags));
209 // FIXME
210}
211
212
213static void
214master_message_part_cb (void *cls, const struct GNUNET_PSYC_MessageHeader *msg,
215 const struct GNUNET_MessageHeader *pmsg)
216{
217 GNUNET_assert (NULL != msg && NULL != pmsg);
218
219 uint64_t message_id = GNUNET_ntohll (msg->message_id);
220 uint32_t flags = ntohl (msg->flags);
221
222 uint16_t type = ntohs (pmsg->type);
223 uint16_t size = ntohs (pmsg->size);
224
225 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
226 "Test #%d: Master got message part of type %u and size %u "
227 "belonging to message ID %" PRIu64 " with flags %x\n",
228 test, type, size, message_id, flags);
229
230 switch (test)
231 {
232 case TEST_SLAVE_TRANSMIT:
233 if (GNUNET_PSYC_MESSAGE_REQUEST != flags)
234 {
235 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
236 "Test #%d: Unexpected request flags: %x" PRIu32 "\n",
237 test, flags);
238 GNUNET_assert (0);
239 return;
240 }
241 // FIXME: check rest of message
242
243 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END == type)
244 master_transmit ();
245 break;
246
247 case TEST_MASTER_TRANSMIT:
248 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END == type && 2 == ++end_count)
249 master_history_replay_latest ();
250 break;
251
252 case TEST_MASTER_HISTORY_REPLAY:
253 case TEST_MASTER_HISTORY_REPLAY_LATEST:
254 if (GNUNET_PSYC_MESSAGE_HISTORIC != flags)
255 {
256 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
257 "Test #%d: Unexpected flags for historic message: %x" PRIu32 "\n",
258 test, flags);
259 GNUNET_assert (0);
260 return;
261 }
262 break;
263
264 default:
265 GNUNET_assert (0);
266 }
267}
268
269
270static void
271slave_message_cb (void *cls, const struct GNUNET_PSYC_MessageHeader *msg)
272{
273 GNUNET_assert (NULL != msg);
274 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
275 "Test #%d: Slave got PSYC message fragment of size %u "
276 "belonging to message ID %" PRIu64 " with flags %x\n",
277 test, ntohs (msg->header.size),
278 GNUNET_ntohll (msg->message_id), ntohl (msg->flags));
279 // FIXME
280}
281
282
283static void
284slave_message_part_cb (void *cls,
285 const struct GNUNET_PSYC_MessageHeader *msg,
286 const struct GNUNET_MessageHeader *pmsg)
287{
288 GNUNET_assert (NULL != msg && NULL != pmsg);
289
290 uint64_t message_id = GNUNET_ntohll (msg->message_id);
291 uint32_t flags = ntohl (msg->flags);
292
293 uint16_t type = ntohs (pmsg->type);
294 uint16_t size = ntohs (pmsg->size);
295
296 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
297 "Test #%d: Slave got message part of type %u and size %u "
298 "belonging to message ID %" PRIu64 " with flags %x\n",
299 test, type, size, message_id, flags);
300
301 switch (test)
302 {
303 case TEST_MASTER_TRANSMIT:
304 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END == type && 2 == ++end_count)
305 master_history_replay_latest ();
306 break;
307
308 case TEST_SLAVE_HISTORY_REPLAY:
309 case TEST_SLAVE_HISTORY_REPLAY_LATEST:
310 if (GNUNET_PSYC_MESSAGE_HISTORIC != flags)
311 {
312 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
313 "Test #%d: Unexpected flags for historic message: %x" PRIu32 "\n",
314 test, flags);
315 GNUNET_assert (0);
316 return;
317 }
318 break;
319
320 default:
321 GNUNET_assert (0);
322 }
323}
324
325
326static void
327state_get_var (void *cls, const struct GNUNET_MessageHeader *mod,
328 const char *name, const void *value,
329 uint32_t value_size, uint32_t full_value_size)
330{
331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
332 "Got state var: %s\n%.*s\n",
333 name,
334 (int) value_size,
335 (const char *) value);
336}
337
338
339/*** Slave state_get_prefix() ***/
340
341static void
342slave_state_get_prefix_result (void *cls, int64_t result,
343 const void *err_msg, uint16_t err_msg_size)
344{
345 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
346 "Test #%d: slave_state_get_prefix:\t%" PRId64 " (%.*s)\n",
347 test, result,
348 (int) err_msg_size,
349 (const char *) err_msg);
350 // FIXME: GNUNET_assert (2 == result);
351 end ();
352}
353
354
355static void
356slave_state_get_prefix ()
357{
358 test = TEST_SLAVE_STATE_GET_PREFIX;
359 GNUNET_PSYC_channel_state_get_prefix (slv_chn, "_foo", state_get_var,
360 slave_state_get_prefix_result, NULL);
361}
362
363
364/*** Master state_get_prefix() ***/
365
366
367static void
368master_state_get_prefix_result (void *cls, int64_t result,
369 const void *err_msg, uint16_t err_msg_size)
370{
371 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
372 "Test #%d: master_state_get_prefix:\t%" PRId64 " (%s)\n",
373 test, result, (char *) err_msg);
374 // FIXME: GNUNET_assert (2 == result);
375 slave_state_get_prefix ();
376}
377
378
379static void
380master_state_get_prefix ()
381{
382 test = TEST_MASTER_STATE_GET_PREFIX;
383 GNUNET_PSYC_channel_state_get_prefix (mst_chn, "_foo", state_get_var,
384 master_state_get_prefix_result, NULL);
385}
386
387
388/*** Slave state_get() ***/
389
390
391static void
392slave_state_get_result (void *cls, int64_t result,
393 const void *err_msg, uint16_t err_msg_size)
394{
395 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
396 "Test #%d: slave_state_get:\t%" PRId64 " (%.*s)\n",
397 test, result, err_msg_size, (char *) err_msg);
398 // FIXME: GNUNET_assert (2 == result);
399 master_state_get_prefix ();
400}
401
402
403static void
404slave_state_get ()
405{
406 test = TEST_SLAVE_STATE_GET;
407 GNUNET_PSYC_channel_state_get (slv_chn, "_foo_bar_baz", state_get_var,
408 slave_state_get_result, NULL);
409}
410
411
412/*** Master state_get() ***/
413
414
415static void
416master_state_get_result (void *cls, int64_t result,
417 const void *err_msg, uint16_t err_msg_size)
418{
419 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
420 "Test #%d: master_state_get:\t%" PRId64 " (%.*s)\n",
421 test, result, err_msg_size, (char *) err_msg);
422 // FIXME: GNUNET_assert (1 == result);
423 slave_state_get ();
424}
425
426
427static void
428master_state_get ()
429{
430 test = TEST_MASTER_STATE_GET;
431 GNUNET_PSYC_channel_state_get (mst_chn, "_foo_bar_baz", state_get_var,
432 master_state_get_result, NULL);
433}
434
435
436/*** Slave history_replay() ***/
437
438static void
439slave_history_replay_result (void *cls, int64_t result,
440 const void *err_msg, uint16_t err_msg_size)
441{
442 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
443 "Test #%d: slave_history_replay:\t%" PRId64 " (%.*s)\n",
444 test, result,
445 (int) err_msg_size,
446 (const char *) err_msg);
447 GNUNET_assert (9 == result);
448
449 master_state_get ();
450}
451
452
453static void
454slave_history_replay ()
455{
456 test = TEST_SLAVE_HISTORY_REPLAY;
457 GNUNET_PSYC_channel_history_replay (slv_chn, 1, 1, "",
458 GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
459 slave_message_cb,
460 slave_message_part_cb,
461 slave_history_replay_result, NULL);
462}
463
464
465/*** Master history_replay() ***/
466
467
468static void
469master_history_replay_result (void *cls, int64_t result,
470 const void *err_msg, uint16_t err_msg_size)
471{
472 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
473 "Test #%d: master_history_replay:\t%" PRId64 " (%.*s)\n",
474 test, result,
475 (int) err_msg_size,
476 (const char *) err_msg);
477 GNUNET_assert (9 == result);
478
479 slave_history_replay ();
480}
481
482
483static void
484master_history_replay ()
485{
486 test = TEST_MASTER_HISTORY_REPLAY;
487 GNUNET_PSYC_channel_history_replay (mst_chn, 1, 1, "",
488 GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
489 master_message_cb,
490 master_message_part_cb,
491 master_history_replay_result, NULL);
492}
493
494
495/*** Slave history_replay_latest() ***/
496
497
498static void
499slave_history_replay_latest_result (void *cls, int64_t result,
500 const void *err_msg, uint16_t err_msg_size)
501{
502 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
503 "Test #%d: slave_history_replay_latest:\t%" PRId64 " (%.*s)\n",
504 test, result,
505 (int) err_msg_size,
506 (const char *) err_msg);
507 GNUNET_assert (9 == result);
508
509 master_history_replay ();
510}
511
512
513static void
514slave_history_replay_latest ()
515{
516 test = TEST_SLAVE_HISTORY_REPLAY_LATEST;
517 GNUNET_PSYC_channel_history_replay_latest (slv_chn, 1, "",
518 GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
519 &slave_message_cb,
520 &slave_message_part_cb,
521 &slave_history_replay_latest_result,
522 NULL);
523}
524
525
526/*** Master history_replay_latest() ***/
527
528
529static void
530master_history_replay_latest_result (void *cls, int64_t result,
531 const void *err_msg, uint16_t err_msg_size)
532{
533 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
534 "Test #%d: master_history_replay_latest:\t%" PRId64 " (%.*s)\n",
535 test, result, err_msg_size, (char *) err_msg);
536 GNUNET_assert (9 == result);
537
538 slave_history_replay_latest ();
539}
540
541
542static void
543master_history_replay_latest ()
544{
545 test = TEST_MASTER_HISTORY_REPLAY_LATEST;
546 GNUNET_PSYC_channel_history_replay_latest (mst_chn, 1, "",
547 GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
548 &master_message_cb,
549 &master_message_part_cb,
550 &master_history_replay_latest_result,
551 NULL);
552}
553
554
555static void
556transmit_resume (void *cls)
557{
558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
559 "Test #%d: Transmission resumed.\n", test);
560 struct TransmitClosure *tmit = cls;
561 if (NULL != tmit->mst_tmit)
562 GNUNET_PSYC_master_transmit_resume (tmit->mst_tmit);
563 else
564 GNUNET_PSYC_slave_transmit_resume (tmit->slv_tmit);
565}
566
567
568static int
569tmit_notify_data (void *cls, uint16_t *data_size, void *data)
570{
571 struct TransmitClosure *tmit = cls;
572 if (0 == tmit->data_count)
573 {
574 *data_size = 0;
575 return GNUNET_YES;
576 }
577
578 uint16_t size = strlen (tmit->data[tmit->n]);
579 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
580 "Test #%d: Transmit notify data: %u bytes available, "
581 "processing fragment %u/%u (size %u).\n",
582 test, *data_size, tmit->n + 1, tmit->data_count, size);
583 if (*data_size < size)
584 {
585 *data_size = 0;
586 GNUNET_assert (0);
587 return GNUNET_SYSERR;
588 }
589
590 if (GNUNET_YES != tmit->paused && 0 < tmit->data_delay[tmit->n])
591 {
592 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
593 "Test #%d: Transmission paused.\n", test);
594 tmit->paused = GNUNET_YES;
595 GNUNET_SCHEDULER_add_delayed (
596 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
597 tmit->data_delay[tmit->n]),
598 &transmit_resume, tmit);
599 *data_size = 0;
600 return GNUNET_NO;
601 }
602 tmit->paused = GNUNET_NO;
603
604 *data_size = size;
605 GNUNET_memcpy (data, tmit->data[tmit->n], size);
606
607 return ++tmit->n < tmit->data_count ? GNUNET_NO : GNUNET_YES;
608}
609
610
611static int
612tmit_notify_mod (void *cls, uint16_t *data_size, void *data, uint8_t *oper,
613 uint32_t *full_value_size)
614{
615 struct TransmitClosure *tmit = cls;
616 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
617 "Test #%d: Transmit notify modifier: %u bytes available, "
618 "%u modifiers left to process.\n",
619 test, *data_size, (unsigned int) GNUNET_PSYC_env_get_count (tmit->env));
620
621 uint16_t name_size = 0;
622 size_t value_size = 0;
623 const char *value = NULL;
624
625 if (NULL != oper && NULL != tmit->mod)
626 { /* New modifier */
627 tmit->mod = tmit->mod->next;
628 if (NULL == tmit->mod)
629 { /* No more modifiers, continue with data */
630 *data_size = 0;
631 return GNUNET_YES;
632 }
633
634 GNUNET_assert (tmit->mod->value_size < UINT32_MAX);
635 *full_value_size = tmit->mod->value_size;
636 *oper = tmit->mod->oper;
637 name_size = strlen (tmit->mod->name);
638
639 if (name_size + 1 + tmit->mod->value_size <= *data_size)
640 {
641 *data_size = name_size + 1 + tmit->mod->value_size;
642 }
643 else
644 {
645 tmit->mod_value_size = tmit->mod->value_size;
646 value_size = *data_size - name_size - 1;
647 tmit->mod_value_size -= value_size;
648 tmit->mod_value = tmit->mod->value + value_size;
649 }
650
651 GNUNET_memcpy (data, tmit->mod->name, name_size);
652 ((char *)data)[name_size] = '\0';
653 GNUNET_memcpy ((char *)data + name_size + 1, tmit->mod->value, value_size);
654 }
655 else if (NULL != tmit->mod_value && 0 < tmit->mod_value_size)
656 { /* Modifier continuation */
657 value = tmit->mod_value;
658 if (tmit->mod_value_size <= *data_size)
659 {
660 value_size = tmit->mod_value_size;
661 tmit->mod_value = NULL;
662 }
663 else
664 {
665 value_size = *data_size;
666 tmit->mod_value += value_size;
667 }
668 tmit->mod_value_size -= value_size;
669
670 if (*data_size < value_size)
671 {
672 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
673 "value larger than buffer: %u < %zu\n",
674 *data_size, value_size);
675 *data_size = 0;
676 return GNUNET_NO;
677 }
678
679 *data_size = value_size;
680 GNUNET_memcpy (data, value, value_size);
681 }
682
683 return GNUNET_NO;
684}
685
686
687static void
688slave_join ();
689
690
691static void
692slave_transmit ()
693{
694 test = TEST_SLAVE_TRANSMIT;
695 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
696 "Test #%d: Slave sending request to master.\n", test);
697
698 tmit = GNUNET_new (struct TransmitClosure);
699 tmit->env = GNUNET_PSYC_env_create ();
700 GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN,
701 "_abc", "abc def", 7);
702 GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN,
703 "_abc_def", "abc def ghi", 11);
704 tmit->mod = GNUNET_PSYC_env_head (tmit->env);
705 tmit->n = 0;
706 tmit->data[0] = "slave test";
707 tmit->data_count = 1;
708 tmit->slv_tmit
709 = GNUNET_PSYC_slave_transmit (slv, "_request_test", &tmit_notify_mod,
710 &tmit_notify_data, tmit,
711 GNUNET_PSYC_SLAVE_TRANSMIT_NONE);
712}
713
714
715static void
716slave_remove_cb (void *cls, int64_t result,
717 const void *err_msg, uint16_t err_msg_size)
718{
719 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
720 "Test #%d: slave_remove:\t%" PRId64 " (%.*s)\n",
721 test, result, err_msg_size, (char *) err_msg);
722
723 slave_transmit ();
724}
725
726
727static void
728slave_remove ()
729{
730 test = TEST_SLAVE_REMOVE;
731 struct GNUNET_PSYC_Channel *chn = GNUNET_PSYC_master_get_channel (mst);
732 GNUNET_PSYC_channel_slave_remove (chn, &slave_pub_key, 2,
733 &slave_remove_cb, chn);
734}
735
736
737static void
738slave_add_cb (void *cls, int64_t result,
739 const void *err_msg, uint16_t err_msg_size)
740{
741 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
742 "Test #%d: slave_add:\t%" PRId64 " (%.*s)\n",
743 test, result, err_msg_size, (char *) err_msg);
744 slave_remove ();
745}
746
747
748static void
749slave_add ()
750{
751 test = TEST_SLAVE_ADD;
752 struct GNUNET_PSYC_Channel *chn = GNUNET_PSYC_master_get_channel (mst);
753 GNUNET_PSYC_channel_slave_add (chn, &slave_pub_key, 2, 2, &slave_add_cb, chn);
754}
755
756
757static void
758schedule_second_slave_join (void *cls)
759{
760 slave_join (TEST_SLAVE_JOIN_ACCEPT);
761}
762
763
764static void
765first_slave_parted (void *cls)
766{
767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "First slave parted.\n");
768 GNUNET_SCHEDULER_add_now (&schedule_second_slave_join, NULL);
769}
770
771
772static void
773schedule_first_slave_part (void *cls)
774{
775 GNUNET_PSYC_slave_part (slv, GNUNET_NO, &first_slave_parted, NULL);
776}
777
778
779static void
780join_decision_cb (void *cls,
781 const struct GNUNET_PSYC_JoinDecisionMessage *dcsn,
782 int is_admitted,
783 const struct GNUNET_PSYC_Message *join_msg)
784{
785 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
786 "Test #%d: Slave got join decision: %d\n", test, is_admitted);
787
788 switch (test)
789 {
790 case TEST_SLAVE_JOIN_REJECT:
791 GNUNET_assert (0 == is_admitted);
792 GNUNET_assert (1 == join_req_count);
793 GNUNET_SCHEDULER_add_now (&schedule_first_slave_part, NULL);
794 break;
795
796 case TEST_SLAVE_JOIN_ACCEPT:
797 GNUNET_assert (1 == is_admitted);
798 GNUNET_assert (2 == join_req_count);
799 slave_add ();
800 break;
801
802 default:
803 GNUNET_break (0);
804 }
805}
806
807
808static void
809join_request_cb (void *cls,
810 const struct GNUNET_PSYC_JoinRequestMessage *req,
811 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
812 const struct GNUNET_PSYC_Message *join_msg,
813 struct GNUNET_PSYC_JoinHandle *jh)
814{
815 struct GNUNET_HashCode slave_key_hash;
816 GNUNET_CRYPTO_hash (slave_key, sizeof (*slave_key), &slave_key_hash);
817 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
818 "Test #%d: Got join request #%u from %s.\n",
819 test, join_req_count, GNUNET_h2s (&slave_key_hash));
820
821 /* Reject first request */
822 int is_admitted = (0 < join_req_count++) ? GNUNET_YES : GNUNET_NO;
823 GNUNET_PSYC_join_decision (jh, is_admitted, 0, NULL, NULL);
824}
825
826
827static void
828slave_connect_cb (void *cls, int result, uint64_t max_message_id)
829{
830 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
831 "Test #%d: Slave connected: %d, max_message_id: %" PRIu64 "\n",
832 test, result, max_message_id);
833 GNUNET_assert (TEST_SLAVE_JOIN_REJECT == test || TEST_SLAVE_JOIN_ACCEPT == test);
834 GNUNET_assert (GNUNET_OK == result || GNUNET_NO == result);
835}
836
837
838static void
839slave_join (int t)
840{
841 test = t;
842 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
843 "Test #%d: Joining slave.\n", t);
844
845 struct GNUNET_PeerIdentity origin = this_peer;
846 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
847 GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN,
848 "_foo", "bar baz", 7);
849 GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN,
850 "_foo_bar", "foo bar baz", 11);
851 struct GNUNET_PSYC_Message *
852 join_msg = GNUNET_PSYC_message_create ("_request_join", env, "some data", 9);
853
854 slv = GNUNET_PSYC_slave_join (cfg,
855 &channel_pub_key,
856 slave_key,
857 GNUNET_PSYC_SLAVE_JOIN_NONE,
858 &origin,
859 0,
860 NULL,
861 &slave_message_cb,
862 &slave_message_part_cb,
863 &slave_connect_cb,
864 &join_decision_cb,
865 NULL,
866 join_msg);
867 GNUNET_free (join_msg);
868 slv_chn = GNUNET_PSYC_slave_get_channel (slv);
869 GNUNET_PSYC_env_destroy (env);
870}
871
872
873static void
874master_transmit ()
875{
876 test = TEST_MASTER_TRANSMIT;
877 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
878 "Test #%d: Master sending message to all.\n", test);
879 end_count = 0;
880
881 uint32_t i, j;
882
883 char *name_max = "_test_max";
884 uint8_t name_max_size = sizeof ("_test_max");
885 char *val_max = GNUNET_malloc (GNUNET_PSYC_MODIFIER_MAX_PAYLOAD);
886 for (i = 0; i < GNUNET_PSYC_MODIFIER_MAX_PAYLOAD; i++)
887 val_max[i] = (0 == i % 10000) ? '0' + i / 10000 : '.';
888
889 char *name_cont = "_test_cont";
890 uint8_t name_cont_size = sizeof ("_test_cont");
891 char *val_cont = GNUNET_malloc (GNUNET_PSYC_MODIFIER_MAX_PAYLOAD
892 + GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD);
893 for (i = 0; i < GNUNET_PSYC_MODIFIER_MAX_PAYLOAD - name_cont_size; i++)
894 val_cont[i] = (0 == i % 10000) ? '0' + i / 10000 : ':';
895 for (j = 0; j < GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD; j++, i++)
896 val_cont[i] = (0 == j % 10000) ? '0' + j / 10000 : '!';
897
898 tmit = GNUNET_new (struct TransmitClosure);
899 tmit->env = GNUNET_PSYC_env_create ();
900 GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN,
901 "_foo", "bar baz", 7);
902 GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN,
903 name_max, val_max,
904 GNUNET_PSYC_MODIFIER_MAX_PAYLOAD
905 - name_max_size);
906 GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN,
907 "_foo_bar", "foo bar baz", 11);
908 GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN,
909 name_cont, val_cont,
910 GNUNET_PSYC_MODIFIER_MAX_PAYLOAD - name_cont_size
911 + GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD);
912 tmit->mod = GNUNET_PSYC_env_head (tmit->env);
913 tmit->data[0] = "foo";
914 tmit->data[1] = GNUNET_malloc (GNUNET_PSYC_DATA_MAX_PAYLOAD + 1);
915 for (i = 0; i < GNUNET_PSYC_DATA_MAX_PAYLOAD; i++)
916 tmit->data[1][i] = (0 == i % 10000) ? '0' + i / 10000 : '_';
917 tmit->data[2] = "foo bar";
918 tmit->data[3] = "foo bar baz";
919 tmit->data_delay[1] = 3;
920 tmit->data_count = 4;
921 tmit->mst_tmit
922 = GNUNET_PSYC_master_transmit (mst, "_notice_test", &tmit_notify_mod,
923 &tmit_notify_data, tmit,
924 GNUNET_PSYC_MASTER_TRANSMIT_INC_GROUP_GEN);
925}
926
927
928static void
929master_start_cb (void *cls, int result, uint64_t max_message_id)
930{
931 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
932 "Test #%d: Master started: %d, max_message_id: %" PRIu64 "\n",
933 test, result, max_message_id);
934 GNUNET_assert (TEST_MASTER_START == test);
935 GNUNET_assert (GNUNET_OK == result || GNUNET_NO == result);
936 slave_join (TEST_SLAVE_JOIN_REJECT);
937}
938
939
940static void
941master_start ()
942{
943 test = TEST_MASTER_START;
944 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
945 "Test #%d: Starting master.\n", test);
946 mst = GNUNET_PSYC_master_start (cfg, channel_key, GNUNET_PSYC_CHANNEL_PRIVATE,
947 &master_start_cb, &join_request_cb,
948 &master_message_cb, &master_message_part_cb,
949 NULL);
950 mst_chn = GNUNET_PSYC_master_get_channel (mst);
951}
952
953
954static void
955schedule_master_start (void *cls)
956{
957 master_start ();
958}
959
960
961/**
962 * Main function of the test, run from scheduler.
963 *
964 * @param cls NULL
965 * @param cfg configuration we use (also to connect to PSYC service)
966 * @param peer handle to access more of the peer (not used)
967 */
968static void
969#if DEBUG_TEST_PSYC
970run (void *cls, char *const *args, const char *cfgfile,
971 const struct GNUNET_CONFIGURATION_Handle *c)
972#else
973run (void *cls,
974 const struct GNUNET_CONFIGURATION_Handle *c,
975 struct GNUNET_TESTING_Peer *peer)
976#endif
977{
978 cfg = c;
979 end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
980
981 GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer);
982
983 channel_key = GNUNET_CRYPTO_eddsa_key_create ();
984 slave_key = GNUNET_CRYPTO_ecdsa_key_create ();
985
986 GNUNET_CRYPTO_eddsa_key_get_public (channel_key, &channel_pub_key);
987 GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key);
988
989#if DEBUG_TEST_PSYC
990 master_start ();
991#else
992 /* Allow some time for the services to initialize. */
993 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
994 &schedule_master_start, NULL);
995#endif
996}
997
998
999int
1000main (int argc, char *argv[])
1001{
1002 res = 1;
1003#if DEBUG_TEST_PSYC
1004 const struct GNUNET_GETOPT_CommandLineOption opts[] = {
1005 GNUNET_GETOPT_OPTION_END
1006 };
1007 if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-psyc",
1008 "test-psyc [options]",
1009 opts, &run, NULL))
1010 return 1;
1011#else
1012 if (0 != GNUNET_TESTING_peer_run ("test-psyc", "test_psyc.conf", &run, NULL))
1013 return 1;
1014#endif
1015 return res;
1016}
1017
1018/* 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 @@
1@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf
2
3[testbed]
4HOSTNAME = localhost
5OVERLAY_TOPOLOGY = STAR
6
7[peerinfo]
8# Option to disable all disk IO; only useful for testbed runs
9# (large-scale experiments); disables persistence of HELLOs!
10NO_IO = YES
11
12[cadet]
13ID_ANNOUNCE_TIME = 5 s
14
15[nat]
16ENABLE_UPNP = NO
17
18[psyc]
19IMMEDIATE_START = YES
20START_ON_DEMAND = YES
21
22[multicast]
23IMMEDIATE_START = YES
24START_ON_DEMAND = YES
25
26[psycstore]
27IMMEDIATE_START = YES
28START_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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file psyc/test_psyc2.c
23 * @brief Testbed test for the PSYC API.
24 * @author xrs
25 */
26
27#include "platform.h"
28#include "gnunet_crypto_lib.h"
29#include "gnunet_common.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_testbed_service.h"
32#include "gnunet_psyc_util_lib.h"
33#include "gnunet_psyc_service.h"
34
35#define PEERS_REQUESTED 2
36
37static int result;
38
39static struct GNUNET_SCHEDULER_Task *timeout_tid;
40static struct pctx **pctx;
41
42static struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key;
43static struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key;
44
45static struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key;
46static struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key;
47
48/**
49 * Task To perform tests
50 */
51static struct GNUNET_SCHEDULER_Task *test_task;
52
53/**
54 * Peer id couter
55 */
56static unsigned int pids;
57
58struct pctx
59{
60 int idx;
61 struct GNUNET_TESTBED_Peer *peer;
62 const struct GNUNET_PeerIdentity *id;
63
64 struct GNUNET_TESTBED_Operation *op;
65
66 /**
67 * psyc service handle
68 */
69 void *psyc;
70 struct GNUNET_PSYC_Master *mst;
71 struct GNUNET_PSYC_Slave *slv;
72
73 /**
74 * result for test on peer
75 */
76 int test_ok;
77};
78
79static void
80shutdown_task (void *cls)
81{
82 if (NULL != pctx)
83 {
84 if (NULL != pctx[0]->mst)
85 GNUNET_PSYC_master_stop (pctx[0]->mst, GNUNET_NO, NULL, NULL);
86
87 for (int i=0; i < PEERS_REQUESTED; i++)
88 {
89 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Operation done.\n");
90 GNUNET_TESTBED_operation_done (pctx[i]->op);
91 GNUNET_free_non_null (pctx[i]);
92 }
93 GNUNET_free (pctx);
94 }
95
96 if (NULL != timeout_tid)
97 GNUNET_SCHEDULER_cancel (timeout_tid);
98}
99
100static void
101timeout_task (void *cls)
102{
103 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout!\n");
104 result = GNUNET_SYSERR;
105 GNUNET_SCHEDULER_shutdown ();
106}
107
108static void
109start_test (void *cls)
110{
111}
112
113static void
114pinfo_cb (void *cls,
115 struct GNUNET_TESTBED_Operation *operation,
116 const struct GNUNET_TESTBED_PeerInformation *pinfo,
117 const char *emsg)
118{
119 struct pctx *pc = (struct pctx*) cls;
120
121 pc->id = pinfo->result.id;
122
123 pids++;
124 if (pids < (PEERS_REQUESTED - 1))
125 return;
126 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got all IDs, starting test\n");
127 test_task = GNUNET_SCHEDULER_add_now (&start_test, NULL);
128}
129
130static void
131mst_start_cb ()
132{
133}
134
135static void
136join_request_cb ()
137{
138}
139
140static void
141mst_message_cb ()
142{
143}
144
145static void
146mst_message_part_cb ()
147{
148}
149
150static void
151slv_message_cb ()
152{
153}
154
155static void
156slv_message_part_cb ()
157{
158}
159
160static void
161slv_connect_cb ()
162{
163}
164
165static void
166join_decision_cb ()
167{
168}
169
170static void *
171psyc_ca (void *cls,
172 const struct GNUNET_CONFIGURATION_Handle *cfg)
173{
174 struct GNUNET_PSYC_Message *join_msg = NULL;
175 struct pctx *pc = (struct pctx *) cls;
176
177 if (0 == pc->idx)
178 {
179 pc->mst = GNUNET_PSYC_master_start (cfg, channel_key,
180 GNUNET_PSYC_CHANNEL_PRIVATE,
181 &mst_start_cb, &join_request_cb,
182 &mst_message_cb, &mst_message_part_cb,
183 NULL);
184 return pc->mst;
185 }
186
187 pc->slv = GNUNET_PSYC_slave_join (cfg, &channel_pub_key, slave_key,
188 GNUNET_PSYC_SLAVE_JOIN_NONE,
189 &pid, 0, NULL, &slv_message_cb,
190 &slv_message_part_cb,
191 &slv_connect_cb, &join_decision_cb,
192 NULL, join_msg);
193 return pc->slv;
194}
195
196static void
197psyc_da (void *cls,
198 void *op_result)
199{
200 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Disconnected from service.\n");
201}
202
203static void
204service_connect (void *cls,
205 struct GNUNET_TESTBED_Operation *op,
206 void *ca_result,
207 const char *emsg)
208{
209 struct pctx *pc = (struct pctx *) cls;
210
211 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
212 "Connected to service\n");
213
214 GNUNET_assert (NULL != ca_result);
215
216 // FIXME: we need a simple service handle to connect to the service, then
217 // get peer information and AFTER that make PSYC ops. Compare to CADET.
218 pc->psyc = ca_result;
219
220 GNUNET_TESTBED_peer_get_information (pc->peer,
221 GNUNET_TESTBED_PIT_IDENTITY,
222 pinfo_cb, pc);
223}
224
225static void
226testbed_master (void *cls,
227 struct GNUNET_TESTBED_RunHandle *h,
228 unsigned int num_peers,
229 struct GNUNET_TESTBED_Peer **p,
230 unsigned int links_succeeded,
231 unsigned int links_failed)
232{
233 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to testbed_master()\n");
234
235 // Create ctx for peers
236 pctx = GNUNET_new_array (PEERS_REQUESTED, struct pctx*);
237 for (int i = 0; i<PEERS_REQUESTED; i++)
238 {
239 pctx[i] = GNUNET_new (struct pctx);
240 pctx[i]->idx = i;
241 pctx[i]->peer = p[i];
242 pctx[i]->id = NULL;
243 pctx[i]->mst = NULL;
244 pctx[i]->op = NULL;
245 pctx[i]->test_ok = GNUNET_NO;
246 }
247
248 channel_key = GNUNET_CRYPTO_eddsa_key_create ();
249 slave_key = GNUNET_CRYPTO_ecdsa_key_create ();
250
251 GNUNET_CRYPTO_eddsa_key_get_public (channel_key, &channel_pub_key);
252 GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key);
253
254 pctx[0]->op =
255 GNUNET_TESTBED_service_connect (NULL, p[0], "psyc", service_connect,
256 pctx[0], psyc_ca, psyc_da, pctx[0]);
257
258 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
259
260 timeout_tid =
261 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5),
262 &timeout_task, NULL);
263}
264
265int
266main (int argc, char *argv[])
267{
268 int ret;
269
270 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "test\n");
271
272 result = GNUNET_SYSERR;
273
274 ret = GNUNET_TESTBED_test_run ("test-psyc2", "test_psyc.conf",
275 PEERS_REQUESTED, 0LL, NULL, NULL,
276 testbed_master, NULL);
277
278 if ((GNUNET_OK != ret) || (GNUNET_OK != result))
279 return 1;
280
281 return 0;
282}
283
284/* 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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file psyc/test_psyc_api_join.c
23 * @brief Testbed test for the PSYC API.
24 * @author xrs
25 */
26
27/**
28 * Lessons Learned:
29 * - define topology in config
30 * - psyc slave join needs part to end (same with master)
31 * - GNUNET_SCHEDULER_add_delayed return value will outdate at call time
32 * - main can not contain GNUNET_log()
33 */
34
35#include "platform.h"
36#include "gnunet_crypto_lib.h"
37#include "gnunet_common.h"
38#include "gnunet_util_lib.h"
39#include "gnunet_testbed_service.h"
40#include "gnunet_psyc_util_lib.h"
41#include "gnunet_psyc_service.h"
42#include "psyc_test_lib.h"
43
44static struct pctx PEERS[2];
45
46static int pids;
47
48
49static void
50shutdown_task (void *cls)
51{
52 if (NULL != timeout_task_id) {
53 GNUNET_SCHEDULER_cancel (timeout_task_id);
54 timeout_task_id = NULL;
55 }
56
57 for (int i=0;i<2;i++) {
58 GNUNET_free (PEERS[i].channel_pub_key);
59
60 if (NULL != PEERS[i].psyc)
61 {
62 if (0 == i)
63 GNUNET_PSYC_master_stop (PEERS[i].psyc, GNUNET_NO, NULL, NULL);
64 else
65 GNUNET_PSYC_slave_part (PEERS[i].psyc, GNUNET_NO, NULL, NULL);
66 }
67 }
68
69 for (int i=0;i<MAX_TESTBED_OPS;i++)
70 if (NULL != op[i])
71 GNUNET_TESTBED_operation_done (op[i]);
72
73 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shut down!\n");
74}
75
76static void
77timeout_task (void *cls)
78{
79 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Timeout!\n");
80
81 timeout_task_id = NULL;
82
83 result = GNUNET_SYSERR;
84 GNUNET_SCHEDULER_shutdown ();
85}
86
87static void
88join_decision_cb (void *cls,
89 const struct GNUNET_PSYC_JoinDecisionMessage *dcsn,
90 int is_admitted,
91 const struct GNUNET_PSYC_Message *join_msg)
92{
93 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
94 "slave: got join decision: %s\n",
95 (GNUNET_YES == is_admitted) ? "admitted":"rejected");
96
97 result = (GNUNET_YES == is_admitted) ? GNUNET_OK : GNUNET_SYSERR;
98
99 GNUNET_SCHEDULER_shutdown ();
100}
101
102static void
103join_request_cb (void *cls,
104 const struct GNUNET_PSYC_JoinRequestMessage *req,
105 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
106 const struct GNUNET_PSYC_Message *join_msg,
107 struct GNUNET_PSYC_JoinHandle *jh)
108{
109 struct GNUNET_HashCode slave_key_hash;
110
111 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "master: got join request.\n");
112
113 GNUNET_CRYPTO_hash (slave_key, sizeof (*slave_key), &slave_key_hash);
114
115 GNUNET_PSYC_join_decision (jh, GNUNET_YES, 0, NULL, NULL);
116}
117
118static void
119psyc_da ()
120{
121 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "disconnect form PSYC service\n");
122}
123
124static void *
125psyc_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
126{
127 struct pctx *peer = (struct pctx*) cls;
128
129 // Case: master role
130 if (0 == peer->idx) {
131 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting to PSYC as master ...\n");
132
133 peer->psyc = (struct GNUNET_PSYC_Master *)
134 GNUNET_PSYC_master_start (cfg,
135 peer->channel_key,
136 GNUNET_PSYC_CHANNEL_PRIVATE,
137 NULL,
138 join_request_cb,
139 NULL,
140 NULL,
141 cls);
142 return peer->psyc;
143 }
144
145 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting to PSYC as slave ...\n");
146
147 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
148 GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN, "_foo", "bar baz", 7);
149 GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN, "_foo_bar", "foo bar baz", 11);
150
151 struct GNUNET_PSYC_Message *
152 join_msg = GNUNET_PSYC_message_create ("_request_join", env, "some data", 40);
153
154 peer->psyc = (struct GNUNET_PSYC_Slave *)
155 GNUNET_PSYC_slave_join (cfg,
156 peer->channel_pub_key,
157 peer->id_key,
158 GNUNET_PSYC_SLAVE_JOIN_NONE,
159 peer->peer_id_master,
160 0,
161 NULL,
162 NULL,
163 NULL,
164 NULL,
165 join_decision_cb,
166 cls,
167 join_msg);
168
169 GNUNET_free (join_msg);
170 peer->channel = GNUNET_PSYC_slave_get_channel (peer->psyc);
171 GNUNET_PSYC_env_destroy (env);
172
173 return peer->psyc;
174}
175
176static void
177service_connect (void *cls,
178 struct GNUNET_TESTBED_Operation *op,
179 void *ca_result,
180 const char *emsg)
181{
182 GNUNET_assert (NULL != ca_result);
183
184 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to the service\n");
185}
186
187static void
188connect_to_services (void *cls)
189{
190 for (int i = 0; i < 2; i++)
191 {
192 PEERS[i].peer_id_master = PEERS[0].peer_id;
193
194 op[op_cnt++] =
195 GNUNET_TESTBED_service_connect (NULL, PEERS[i].testbed_peer, "psyc",
196 &service_connect, &PEERS[i], &psyc_ca,
197 &psyc_da, &PEERS[i]);
198 }
199}
200
201static void
202pinfo_cb (void *cls,
203 struct GNUNET_TESTBED_Operation *operation,
204 const struct GNUNET_TESTBED_PeerInformation *pinfo,
205 const char *emsg)
206{
207 struct pctx *peer = (struct pctx*) cls;
208
209 peer->peer_id = pinfo->result.id;
210
211 pids++;
212 if (pids < 2)
213 return;
214 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got all IDs, starting test\n");
215
216 GNUNET_SCHEDULER_add_now (&connect_to_services, NULL);
217}
218
219static void
220testbed_master (void *cls,
221 struct GNUNET_TESTBED_RunHandle *h,
222 unsigned int num_peers,
223 struct GNUNET_TESTBED_Peer **p,
224 unsigned int links_succeeded,
225 unsigned int links_failed)
226{
227 struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key = NULL;
228
229 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to testbed_master\n");
230
231 // Set up shutdown logic
232 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
233 timeout_task_id =
234 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 15),
235 &timeout_task, NULL);
236 GNUNET_assert (NULL != timeout_task_id);
237
238 // Set up channel key
239 channel_key = GNUNET_CRYPTO_eddsa_key_create ();
240 GNUNET_assert (NULL != channel_key);
241
242 // Set up information contexts for peers
243 for (int i=0 ; i < 2 ; i++)
244 {
245 PEERS[i].idx = i;
246 PEERS[i].testbed_peer = p[i];
247
248 // Create "egos"
249 PEERS[i].id_key = GNUNET_CRYPTO_ecdsa_key_create ();
250
251 // Set up channel keys shared by master and slave
252 PEERS[i].channel_key = channel_key;
253
254 PEERS[i].channel_pub_key =
255 GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
256 // Get public key
257 GNUNET_CRYPTO_eddsa_key_get_public (PEERS[i].channel_key,
258 PEERS[i].channel_pub_key);
259 // Get peerinfo
260 op[op_cnt++] =
261 GNUNET_TESTBED_peer_get_information (p[i],
262 GNUNET_TESTBED_PIT_IDENTITY,
263 pinfo_cb, &PEERS[i]);
264 }
265}
266
267int
268main (int argc, char *argv[])
269{
270 int ret;
271
272 ret = GNUNET_TESTBED_test_run ("test_psyc_api_join", "test_psyc.conf",
273 2, 0LL, NULL, NULL,
274 &testbed_master, NULL);
275
276 if ( (GNUNET_OK != ret) || (GNUNET_OK != result) )
277 return 1;
278
279 return 0;
280}
281
282/* 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 @@
1gnunet-service-psycstore
2test_plugin_psycstore_mysql
3test_plugin_psycstore_sqlite
4test_plugin_psycstore_postgres
5test_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 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4plugindir = $(libdir)/gnunet
5
6pkgcfgdir= $(pkgdatadir)/config.d/
7
8libexecdir= $(pkglibdir)/libexec/
9
10pkgcfg_DATA = \
11 psycstore.conf
12
13
14if MINGW
15 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
16endif
17
18if USE_COVERAGE
19 AM_CFLAGS = --coverage -O0
20 XLIB = -lgcov
21endif
22
23if HAVE_MYSQL
24MYSQL_PLUGIN = libgnunet_plugin_psycstore_mysql.la
25if HAVE_TESTING
26MYSQL_TESTS = test_plugin_psycstore_mysql
27endif
28endif
29
30if HAVE_POSTGRESQL
31POSTGRES_PLUGIN = libgnunet_plugin_psycstore_postgres.la
32if HAVE_TESTING
33POSTGRES_TESTS = test_plugin_psycstore_postgres
34endif
35endif
36
37if HAVE_SQLITE
38SQLITE_PLUGIN = libgnunet_plugin_psycstore_sqlite.la
39if HAVE_TESTING
40SQLITE_TESTS = test_plugin_psycstore_sqlite
41endif
42endif
43
44lib_LTLIBRARIES = libgnunetpsycstore.la
45
46libgnunetpsycstore_la_SOURCES = \
47 psycstore_api.c \
48 psycstore.h
49libgnunetpsycstore_la_LIBADD = \
50 $(top_builddir)/src/util/libgnunetutil.la \
51 $(GN_LIBINTL) $(XLIB)
52libgnunetpsycstore_la_LDFLAGS = \
53 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
54 -version-info 0:0:0
55
56bin_PROGRAMS =
57
58libexec_PROGRAMS = \
59 gnunet-service-psycstore
60
61gnunet_service_psycstore_SOURCES = \
62 gnunet-service-psycstore.c
63gnunet_service_psycstore_LDADD = \
64 $(top_builddir)/src/statistics/libgnunetstatistics.la \
65 $(top_builddir)/src/util/libgnunetutil.la \
66 $(top_builddir)/src/psycutil/libgnunetpsycutil.la \
67 $(GN_LIBINTL)
68
69plugin_LTLIBRARIES = \
70 $(SQLITE_PLUGIN) \
71 $(MYSQL_PLUGIN) \
72 $(POSTGRES_PLUGIN)
73
74
75libgnunet_plugin_psycstore_mysql_la_SOURCES = \
76 plugin_psycstore_mysql.c
77libgnunet_plugin_psycstore_mysql_la_LIBADD = \
78 libgnunetpsycstore.la \
79 $(top_builddir)/src/my/libgnunetmy.la \
80 $(top_builddir)/src/mysql/libgnunetmysql.la \
81 $(top_builddir)/src/statistics/libgnunetstatistics.la \
82 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
83 $(LTLIBINTL)
84libgnunet_plugin_psycstore_mysql_la_LDFLAGS = \
85 $(GN_PLUGIN_LDFLAGS)
86
87libgnunet_plugin_psycstore_postgres_la_SOURCES = \
88 plugin_psycstore_postgres.c
89libgnunet_plugin_psycstore_postgres_la_LIBADD = \
90 libgnunetpsycstore.la \
91 $(top_builddir)/src/pq/libgnunetpq.la \
92 $(top_builddir)/src/statistics/libgnunetstatistics.la \
93 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq \
94 $(LTLIBINTL)
95libgnunet_plugin_psycstore_postgres_la_LDFLAGS = \
96 $(GN_PLUGIN_LDFLAGS) $(POSTGRESQL_LDFLAGS)
97libgnunet_plugin_psycstore_postgres_la_CPPFLAGS = \
98 $(POSTGRESQL_CPPFLAGS) $(AM_CPPFLAGS)
99
100
101libgnunet_plugin_psycstore_sqlite_la_SOURCES = \
102 plugin_psycstore_sqlite.c
103libgnunet_plugin_psycstore_sqlite_la_LIBADD = \
104 libgnunetpsycstore.la \
105 $(top_builddir)/src/statistics/libgnunetstatistics.la \
106 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \
107 $(LTLIBINTL)
108libgnunet_plugin_psycstore_sqlite_la_LDFLAGS = \
109 $(GN_PLUGIN_LDFLAGS)
110
111
112if HAVE_SQLITE
113if HAVE_TESTING
114check_PROGRAMS = \
115 $(SQLITE_TESTS) \
116 $(MYSQL_TESTS) \
117 $(POSTGRES_TESTS) \
118 test_psycstore
119endif
120endif
121
122if ENABLE_TEST_RUN
123AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
124TESTS = $(check_PROGRAMS)
125endif
126
127test_psycstore_SOURCES = \
128 test_psycstore.c
129test_psycstore_LDADD = \
130 libgnunetpsycstore.la \
131 $(top_builddir)/src/testing/libgnunettesting.la \
132 $(top_builddir)/src/util/libgnunetutil.la
133
134EXTRA_DIST = \
135 test_psycstore.conf
136
137
138test_plugin_psycstore_sqlite_SOURCES = \
139 test_plugin_psycstore.c
140test_plugin_psycstore_sqlite_LDADD = \
141 $(top_builddir)/src/testing/libgnunettesting.la \
142 $(top_builddir)/src/util/libgnunetutil.la
143
144test_plugin_psycstore_mysql_SOURCES = \
145 test_plugin_psycstore.c
146test_plugin_psycstore_mysql_LDADD = \
147 $(top_builddir)/src/testing/libgnunettesting.la \
148 $(top_builddir)/src/util/libgnunetutil.la
149
150test_plugin_psycstore_postgres_SOURCES = \
151 test_plugin_psycstore.c
152test_plugin_psycstore_postgres_LDADD = \
153 $(top_builddir)/src/testing/libgnunettesting.la \
154 $(top_builddir)/src/util/libgnunetutil.la
155
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 @@
1/**
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file psycstore/gnunet-service-psycstore.c
23 * @brief PSYCstore service
24 * @author Gabor X Toth
25 * @author Christian Grothoff
26 */
27
28#include <inttypes.h>
29
30#include "platform.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_constants.h"
33#include "gnunet_protocols.h"
34#include "gnunet_statistics_service.h"
35#include "gnunet_psyc_util_lib.h"
36#include "gnunet_psycstore_service.h"
37#include "gnunet_psycstore_plugin.h"
38#include "psycstore.h"
39
40
41/**
42 * Handle to our current configuration.
43 */
44static const struct GNUNET_CONFIGURATION_Handle *cfg;
45
46/**
47 * Service handle.
48 */
49static struct GNUNET_SERVICE_Handle *service;
50
51/**
52 * Handle to the statistics service.
53 */
54static struct GNUNET_STATISTICS_Handle *stats;
55
56/**
57 * Database handle
58 */
59static struct GNUNET_PSYCSTORE_PluginFunctions *db;
60
61/**
62 * Name of the database plugin
63 */
64static char *db_lib_name;
65
66
67/**
68 * Task run during shutdown.
69 *
70 * @param cls unused
71 */
72static void
73shutdown_task (void *cls)
74{
75 if (NULL != stats)
76 {
77 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
78 stats = NULL;
79 }
80 GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, db));
81 GNUNET_free (db_lib_name);
82 db_lib_name = NULL;
83}
84
85
86/**
87 * Send a result code back to the client.
88 *
89 * @param client
90 * Client that should receive the result code.
91 * @param result_code
92 * Code to transmit.
93 * @param op_id
94 * Operation ID in network byte order.
95 * @param err_msg
96 * Error message to include (or NULL for none).
97 */
98static void
99send_result_code (struct GNUNET_SERVICE_Client *client,
100 uint64_t op_id,
101 int64_t result_code,
102 const char *err_msg)
103{
104 struct OperationResult *res;
105 size_t err_size = 0;
106
107 if (NULL != err_msg)
108 err_size = strnlen (err_msg,
109 GNUNET_MAX_MESSAGE_SIZE - sizeof (*res) - 1) + 1;
110 struct GNUNET_MQ_Envelope *
111 env = GNUNET_MQ_msg_extra (res, err_size,
112 GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE);
113 res->result_code = GNUNET_htonll (result_code - INT64_MIN);
114 res->op_id = op_id;
115 if (0 < err_size)
116 {
117 GNUNET_memcpy (&res[1], err_msg, err_size);
118 ((char *) &res[1])[err_size - 1] = '\0';
119 }
120
121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
122 "Sending result to client: %" PRId64 " (%s)\n",
123 result_code, err_msg);
124 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
125}
126
127
128enum
129{
130 MEMBERSHIP_TEST_NOT_NEEDED = 0,
131 MEMBERSHIP_TEST_NEEDED = 1,
132 MEMBERSHIP_TEST_DONE = 2,
133} MessageMembershipTest;
134
135
136struct SendClosure
137{
138 struct GNUNET_SERVICE_Client *client;
139
140 /**
141 * Channel's public key.
142 */
143 struct GNUNET_CRYPTO_EddsaPublicKey channel_key;
144
145 /**
146 * Slave's public key.
147 */
148 struct GNUNET_CRYPTO_EcdsaPublicKey slave_key;
149
150 /**
151 * Operation ID.
152 */
153 uint64_t op_id;
154
155 /**
156 * Membership test result.
157 */
158 int membership_test_result;
159
160 /**
161 * Do membership test with @a slave_key before returning fragment?
162 * @see enum MessageMembershipTest
163 */
164 uint8_t membership_test;
165};
166
167
168static int
169send_fragment (void *cls, struct GNUNET_MULTICAST_MessageHeader *msg,
170 enum GNUNET_PSYCSTORE_MessageFlags flags)
171{
172 struct SendClosure *sc = cls;
173 struct FragmentResult *res;
174
175 if (MEMBERSHIP_TEST_NEEDED == sc->membership_test)
176 {
177 sc->membership_test = MEMBERSHIP_TEST_DONE;
178 sc->membership_test_result
179 = db->membership_test (db->cls, &sc->channel_key, &sc->slave_key,
180 GNUNET_ntohll (msg->message_id));
181 switch (sc->membership_test_result)
182 {
183 case GNUNET_YES:
184 break;
185
186 case GNUNET_NO:
187 case GNUNET_SYSERR:
188 return GNUNET_NO;
189 }
190 }
191
192 size_t msg_size = ntohs (msg->header.size);
193
194 struct GNUNET_MQ_Envelope *
195 env = GNUNET_MQ_msg_extra (res, msg_size,
196 GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_FRAGMENT);
197 res->op_id = sc->op_id;
198 res->psycstore_flags = htonl (flags);
199 GNUNET_memcpy (&res[1], msg, msg_size);
200 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
201 "Sending fragment %llu to client\n",
202 (unsigned long long) GNUNET_ntohll (msg->fragment_id));
203 GNUNET_free (msg);
204
205 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (sc->client), env);
206 return GNUNET_YES;
207}
208
209
210static int
211send_state_var (void *cls, const char *name,
212 const void *value, uint32_t value_size)
213{
214 struct SendClosure *sc = cls;
215 struct StateResult *res;
216 size_t name_size = strlen (name) + 1;
217
218 /** @todo FIXME: split up value into 64k chunks */
219
220 struct GNUNET_MQ_Envelope *
221 env = GNUNET_MQ_msg_extra (res, name_size + value_size,
222 GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_STATE);
223 res->op_id = sc->op_id;
224 res->name_size = htons (name_size);
225 GNUNET_memcpy (&res[1], name, name_size);
226 GNUNET_memcpy ((char *) &res[1] + name_size, value, value_size);
227 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
228 "Sending state variable %s to client\n", name);
229
230 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (sc->client), env);
231 return GNUNET_OK;
232}
233
234
235static void
236handle_client_membership_store (void *cls,
237 const struct MembershipStoreRequest *req)
238{
239 struct GNUNET_SERVICE_Client *client = cls;
240
241 int ret = db->membership_store (db->cls, &req->channel_key, &req->slave_key,
242 req->did_join,
243 GNUNET_ntohll (req->announced_at),
244 GNUNET_ntohll (req->effective_since),
245 GNUNET_ntohll (req->group_generation));
246
247 if (ret != GNUNET_OK)
248 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
249 _("Failed to store membership information!\n"));
250
251 send_result_code (client, req->op_id, ret, NULL);
252 GNUNET_SERVICE_client_continue (client);
253}
254
255
256static void
257handle_client_membership_test (void *cls,
258 const struct MembershipTestRequest *req)
259{
260 struct GNUNET_SERVICE_Client *client = cls;
261
262 int ret = db->membership_test (db->cls, &req->channel_key, &req->slave_key,
263 GNUNET_ntohll (req->message_id));
264 switch (ret)
265 {
266 case GNUNET_YES:
267 case GNUNET_NO:
268 break;
269 default:
270 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
271 _("Failed to test membership!\n"));
272 }
273
274 send_result_code (client, req->op_id, ret, NULL);
275 GNUNET_SERVICE_client_continue (client);
276}
277
278
279static int
280check_client_fragment_store (void *cls,
281 const struct FragmentStoreRequest *req)
282{
283 return GNUNET_OK;
284}
285
286
287static void
288handle_client_fragment_store (void *cls,
289 const struct FragmentStoreRequest *req)
290{
291 struct GNUNET_SERVICE_Client *client = cls;
292
293 const struct GNUNET_MessageHeader *
294 msg = GNUNET_MQ_extract_nested_mh (req);
295 if (NULL == msg
296 || ntohs (msg->size) < sizeof (struct GNUNET_MULTICAST_MessageHeader))
297 {
298 GNUNET_break (0);
299 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
300 _("Dropping invalid fragment\n"));
301 GNUNET_SERVICE_client_drop (client);
302 return;
303 }
304
305 int ret = db->fragment_store (db->cls, &req->channel_key,
306 (const struct GNUNET_MULTICAST_MessageHeader *)
307 msg, ntohl (req->psycstore_flags));
308
309 if (ret != GNUNET_OK)
310 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
311 _("Failed to store fragment\n"));
312
313 send_result_code (client, req->op_id, ret, NULL);
314 GNUNET_SERVICE_client_continue (client);
315}
316
317
318static void
319handle_client_fragment_get (void *cls,
320 const struct FragmentGetRequest *req)
321{
322 struct GNUNET_SERVICE_Client *client = cls;
323
324 struct SendClosure
325 sc = { .op_id = req->op_id,
326 .client = client,
327 .channel_key = req->channel_key,
328 .slave_key = req->slave_key,
329 .membership_test = req->do_membership_test };
330
331 int64_t ret;
332 uint64_t ret_frags = 0;
333 uint64_t first_fragment_id = GNUNET_ntohll (req->first_fragment_id);
334 uint64_t last_fragment_id = GNUNET_ntohll (req->last_fragment_id);
335 uint64_t limit = GNUNET_ntohll (req->fragment_limit);
336
337 if (0 == limit)
338 ret = db->fragment_get (db->cls, &req->channel_key,
339 first_fragment_id, last_fragment_id,
340 &ret_frags, send_fragment, &sc);
341 else
342 ret = db->fragment_get_latest (db->cls, &req->channel_key, limit,
343 &ret_frags, send_fragment, &sc);
344
345 switch (ret)
346 {
347 case GNUNET_YES:
348 case GNUNET_NO:
349 if (MEMBERSHIP_TEST_DONE == sc.membership_test)
350 {
351 switch (sc.membership_test_result)
352 {
353 case GNUNET_YES:
354 break;
355
356 case GNUNET_NO:
357 ret = GNUNET_PSYCSTORE_MEMBERSHIP_TEST_FAILED;
358 break;
359
360 case GNUNET_SYSERR:
361 ret = GNUNET_SYSERR;
362 break;
363 }
364 }
365 break;
366 default:
367 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
368 _("Failed to get fragment!\n"));
369 }
370 send_result_code (client, req->op_id, (ret < 0) ? ret : ret_frags, NULL);
371 GNUNET_SERVICE_client_continue (client);
372}
373
374
375static int
376check_client_message_get (void *cls,
377 const struct MessageGetRequest *req)
378{
379 return GNUNET_OK;
380}
381
382
383static void
384handle_client_message_get (void *cls,
385 const struct MessageGetRequest *req)
386{
387 struct GNUNET_SERVICE_Client *client = cls;
388
389 uint16_t size = ntohs (req->header.size);
390 const char *method_prefix = (const char *) &req[1];
391
392 if (size < sizeof (*req) + 1
393 || '\0' != method_prefix[size - sizeof (*req) - 1])
394 {
395 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
396 "Message get: invalid method prefix. size: %u < %u?\n",
397 size,
398 (unsigned int) (sizeof (*req) + 1));
399 GNUNET_break (0);
400 GNUNET_SERVICE_client_drop (client);
401 return;
402 }
403
404 struct SendClosure
405 sc = { .op_id = req->op_id,
406 .client = client,
407 .channel_key = req->channel_key,
408 .slave_key = req->slave_key,
409 .membership_test = req->do_membership_test };
410
411 int64_t ret;
412 uint64_t ret_frags = 0;
413 uint64_t first_message_id = GNUNET_ntohll (req->first_message_id);
414 uint64_t last_message_id = GNUNET_ntohll (req->last_message_id);
415 uint64_t msg_limit = GNUNET_ntohll (req->message_limit);
416 uint64_t frag_limit = GNUNET_ntohll (req->fragment_limit);
417
418 /** @todo method_prefix */
419 if (0 == msg_limit)
420 ret = db->message_get (db->cls, &req->channel_key,
421 first_message_id, last_message_id, frag_limit,
422 &ret_frags, send_fragment, &sc);
423 else
424 ret = db->message_get_latest (db->cls, &req->channel_key, msg_limit,
425 &ret_frags, send_fragment, &sc);
426
427 switch (ret)
428 {
429 case GNUNET_YES:
430 case GNUNET_NO:
431 break;
432 default:
433 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
434 _("Failed to get message!\n"));
435 }
436
437 send_result_code (client, req->op_id, (ret < 0) ? ret : ret_frags, NULL);
438 GNUNET_SERVICE_client_continue (client);
439}
440
441
442static void
443handle_client_message_get_fragment (void *cls,
444 const struct MessageGetFragmentRequest *req)
445{
446 struct GNUNET_SERVICE_Client *client = cls;
447
448 struct SendClosure
449 sc = { .op_id = req->op_id, .client = client,
450 .channel_key = req->channel_key, .slave_key = req->slave_key,
451 .membership_test = req->do_membership_test };
452
453 int ret = db->message_get_fragment (db->cls, &req->channel_key,
454 GNUNET_ntohll (req->message_id),
455 GNUNET_ntohll (req->fragment_offset),
456 &send_fragment, &sc);
457 switch (ret)
458 {
459 case GNUNET_YES:
460 case GNUNET_NO:
461 break;
462 default:
463 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
464 _("Failed to get message fragment!\n"));
465 }
466
467 send_result_code (client, req->op_id, ret, NULL);
468 GNUNET_SERVICE_client_continue (client);
469}
470
471
472static void
473handle_client_counters_get (void *cls,
474 const struct OperationRequest *req)
475{
476 struct GNUNET_SERVICE_Client *client = cls;
477
478 struct CountersResult *res;
479 struct GNUNET_MQ_Envelope *
480 env = GNUNET_MQ_msg (res, GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_COUNTERS);
481
482 int ret = db->counters_message_get (db->cls, &req->channel_key,
483 &res->max_fragment_id, &res->max_message_id,
484 &res->max_group_generation);
485 switch (ret)
486 {
487 case GNUNET_OK:
488 ret = db->counters_state_get (db->cls, &req->channel_key,
489 &res->max_state_message_id);
490 case GNUNET_NO:
491 break;
492 default:
493 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
494 _("Failed to get master counters!\n"));
495 }
496
497 res->result_code = htonl (ret);
498 res->op_id = req->op_id;
499 res->max_fragment_id = GNUNET_htonll (res->max_fragment_id);
500 res->max_message_id = GNUNET_htonll (res->max_message_id);
501 res->max_group_generation = GNUNET_htonll (res->max_group_generation);
502 res->max_state_message_id = GNUNET_htonll (res->max_state_message_id);
503
504 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
505 GNUNET_SERVICE_client_continue (client);
506}
507
508
509struct StateModifyClosure
510{
511 const struct GNUNET_CRYPTO_EddsaPublicKey channel_key;
512 struct GNUNET_PSYC_ReceiveHandle *recv;
513 enum GNUNET_PSYC_MessageState msg_state;
514 char mod_oper;
515 char *mod_name;
516 char *mod_value;
517 uint32_t mod_value_size;
518 uint32_t mod_value_remaining;
519};
520
521
522static void
523recv_state_message_part (void *cls,
524 const struct GNUNET_PSYC_MessageHeader *msg,
525 const struct GNUNET_MessageHeader *pmsg)
526{
527 struct StateModifyClosure *scls = cls;
528 uint16_t psize;
529
530 if (NULL == msg)
531 { // FIXME: error on unknown message
532 return;
533 }
534
535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
536 "recv_state_message_part() message_id: %" PRIu64
537 ", fragment_offset: %" PRIu64 ", flags: %u\n",
538 GNUNET_ntohll (msg->message_id),
539 GNUNET_ntohll (msg->fragment_offset),
540 ntohl (msg->flags));
541
542 if (NULL == pmsg)
543 {
544 scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_ERROR;
545 return;
546 }
547
548 switch (ntohs (pmsg->type))
549 {
550 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
551 {
552 scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_METHOD;
553 break;
554 }
555
556 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
557 {
558 struct GNUNET_PSYC_MessageModifier *
559 pmod = (struct GNUNET_PSYC_MessageModifier *) pmsg;
560 psize = ntohs (pmod->header.size);
561 uint16_t name_size = ntohs (pmod->name_size);
562 uint32_t value_size = ntohl (pmod->value_size);
563
564 const char *name = (const char *) &pmod[1];
565 const void *value = name + name_size;
566
567 if (GNUNET_PSYC_OP_SET != pmod->oper)
568 { // Apply non-transient operation.
569 if (psize == sizeof (*pmod) + name_size + value_size)
570 {
571 db->state_modify_op (db->cls, &scls->channel_key,
572 pmod->oper, name, value, value_size);
573 }
574 else
575 {
576 scls->mod_oper = pmod->oper;
577 scls->mod_name = GNUNET_malloc (name_size);
578 GNUNET_memcpy (scls->mod_name, name, name_size);
579
580 scls->mod_value_size = value_size;
581 scls->mod_value = GNUNET_malloc (scls->mod_value_size);
582 scls->mod_value_remaining
583 = scls->mod_value_size - (psize - sizeof (*pmod) - name_size);
584 GNUNET_memcpy (scls->mod_value, value, value_size - scls->mod_value_remaining);
585 }
586 }
587 scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_MODIFIER;
588 break;
589 }
590
591 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
592 if (GNUNET_PSYC_OP_SET != scls->mod_oper)
593 {
594 if (scls->mod_value_remaining == 0)
595 {
596 GNUNET_break_op (0);
597 scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_ERROR;
598 }
599 psize = ntohs (pmsg->size);
600 GNUNET_memcpy (scls->mod_value + (scls->mod_value_size - scls->mod_value_remaining),
601 &pmsg[1], psize - sizeof (*pmsg));
602 scls->mod_value_remaining -= psize - sizeof (*pmsg);
603 if (0 == scls->mod_value_remaining)
604 {
605 db->state_modify_op (db->cls, &scls->channel_key,
606 scls->mod_oper, scls->mod_name,
607 scls->mod_value, scls->mod_value_size);
608 GNUNET_free (scls->mod_name);
609 GNUNET_free (scls->mod_value);
610 scls->mod_oper = 0;
611 scls->mod_name = NULL;
612 scls->mod_value = NULL;
613 scls->mod_value_size = 0;
614 }
615 }
616 scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_MOD_CONT;
617 break;
618
619 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
620 scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_DATA;
621 break;
622
623 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
624 scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_END;
625 break;
626
627 default:
628 scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_ERROR;
629 }
630}
631
632
633static int
634recv_state_fragment (void *cls, struct GNUNET_MULTICAST_MessageHeader *msg,
635 enum GNUNET_PSYCSTORE_MessageFlags flags)
636{
637 struct StateModifyClosure *scls = cls;
638
639 if (NULL == scls->recv)
640 {
641 scls->recv = GNUNET_PSYC_receive_create (NULL, recv_state_message_part,
642 scls);
643 }
644
645 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
646 "recv_state_fragment: %" PRIu64 "\n", GNUNET_ntohll (msg->fragment_id));
647
648 struct GNUNET_PSYC_MessageHeader *
649 pmsg = GNUNET_PSYC_message_header_create (msg, flags);
650 GNUNET_PSYC_receive_message (scls->recv, pmsg);
651 GNUNET_free (pmsg);
652
653 return GNUNET_YES;
654}
655
656
657static void
658handle_client_state_modify (void *cls,
659 const struct StateModifyRequest *req)
660{
661 struct GNUNET_SERVICE_Client *client = cls;
662
663 uint64_t message_id = GNUNET_ntohll (req->message_id);
664 uint64_t state_delta = GNUNET_ntohll (req->state_delta);
665 uint64_t ret_frags = 0;
666 struct StateModifyClosure
667 scls = { .channel_key = req->channel_key };
668
669 int ret = db->state_modify_begin (db->cls, &req->channel_key,
670 message_id, state_delta);
671
672 if (GNUNET_OK != ret)
673 {
674 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
675 _("Failed to begin modifying state: %d\n"), ret);
676 }
677 else
678 {
679 ret = db->message_get (db->cls, &req->channel_key,
680 message_id, message_id, 0,
681 &ret_frags, recv_state_fragment, &scls);
682 if (GNUNET_OK != ret)
683 {
684 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
685 _("Failed to modify state: %d\n"), ret);
686 GNUNET_break (0);
687 }
688 else
689 {
690 if (GNUNET_OK != db->state_modify_end (db->cls, &req->channel_key, message_id))
691 {
692 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
693 _("Failed to end modifying state!\n"));
694 GNUNET_break (0);
695 }
696 }
697 if (NULL != scls.recv)
698 {
699 GNUNET_PSYC_receive_destroy (scls.recv);
700 }
701 }
702
703 send_result_code (client, req->op_id, ret, NULL);
704 GNUNET_SERVICE_client_continue (client);
705}
706
707
708static int
709check_client_state_sync (void *cls,
710 const struct StateSyncRequest *req)
711{
712 return GNUNET_OK;
713}
714
715
716/** @todo FIXME: stop processing further state sync messages after an error */
717static void
718handle_client_state_sync (void *cls,
719 const struct StateSyncRequest *req)
720{
721 struct GNUNET_SERVICE_Client *client = cls;
722
723 int ret = GNUNET_SYSERR;
724 const char *name = (const char *) &req[1];
725 uint16_t name_size = ntohs (req->name_size);
726
727 if (name_size <= 2 || '\0' != name[name_size - 1])
728 {
729 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
730 _("Tried to set invalid state variable name!\n"));
731 GNUNET_break_op (0);
732 }
733 else
734 {
735 ret = GNUNET_OK;
736
737 if (req->flags & STATE_OP_FIRST)
738 {
739 ret = db->state_sync_begin (db->cls, &req->channel_key);
740 }
741 if (ret != GNUNET_OK)
742 {
743 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
744 _("Failed to begin synchronizing state!\n"));
745 }
746 else
747 {
748 ret = db->state_sync_assign (db->cls, &req->channel_key, name,
749 name + ntohs (req->name_size),
750 ntohs (req->header.size) - sizeof (*req)
751 - ntohs (req->name_size));
752 }
753
754 if (GNUNET_OK == ret && req->flags & STATE_OP_LAST)
755 {
756 ret = db->state_sync_end (db->cls, &req->channel_key,
757 GNUNET_ntohll (req->max_state_message_id),
758 GNUNET_ntohll (req->state_hash_message_id));
759 if (ret != GNUNET_OK)
760 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
761 _("Failed to end synchronizing state!\n"));
762 }
763 }
764 send_result_code (client, req->op_id, ret, NULL);
765 GNUNET_SERVICE_client_continue (client);
766}
767
768
769static void
770handle_client_state_reset (void *cls,
771 const struct OperationRequest *req)
772{
773 struct GNUNET_SERVICE_Client *client = cls;
774
775 int ret = db->state_reset (db->cls, &req->channel_key);
776
777 if (ret != GNUNET_OK)
778 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
779 _("Failed to reset state!\n"));
780
781 send_result_code (client, req->op_id, ret, NULL);
782 GNUNET_SERVICE_client_continue (client);
783}
784
785
786static void
787handle_client_state_hash_update (void *cls,
788 const struct StateHashUpdateRequest *req)
789{
790 struct GNUNET_SERVICE_Client *client = cls;
791
792 int ret = db->state_reset (db->cls, &req->channel_key);
793 if (ret != GNUNET_OK)
794 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
795 _("Failed to reset state!\n"));
796
797 send_result_code (client, req->op_id, ret, NULL);
798 GNUNET_SERVICE_client_continue (client);
799}
800
801
802static int
803check_client_state_get (void *cls,
804 const struct OperationRequest *req)
805{
806 return GNUNET_OK;
807}
808
809
810static void
811handle_client_state_get (void *cls,
812 const struct OperationRequest *req)
813{
814 struct GNUNET_SERVICE_Client *client = cls;
815
816 struct SendClosure sc = { .op_id = req->op_id, .client = client };
817 int64_t ret = GNUNET_SYSERR;
818 const char *name = (const char *) &req[1];
819 uint16_t name_size = ntohs (req->header.size) - sizeof (*req);
820
821 if (name_size <= 2 || '\0' != name[name_size - 1])
822 {
823 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
824 _("Tried to get invalid state variable name!\n"));
825 GNUNET_break (0);
826 }
827 else
828 {
829 ret = db->state_get (db->cls, &req->channel_key, name,
830 &send_state_var, &sc);
831 if (GNUNET_NO == ret && name_size >= 5) /* min: _a_b\0 */
832 {
833 char *p, *n = GNUNET_malloc (name_size);
834 GNUNET_memcpy (n, name, name_size);
835 while (&n[1] < (p = strrchr (n, '_')) && GNUNET_NO == ret)
836 {
837 *p = '\0';
838 ret = db->state_get (db->cls, &req->channel_key, n,
839 &send_state_var, &sc);
840 }
841 GNUNET_free (n);
842 }
843 }
844 switch (ret)
845 {
846 case GNUNET_OK:
847 case GNUNET_NO:
848 break;
849 default:
850 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
851 _("Failed to get state variable!\n"));
852 }
853
854 send_result_code (client, req->op_id, ret, NULL);
855 GNUNET_SERVICE_client_continue (client);
856}
857
858
859static int
860check_client_state_get_prefix (void *cls,
861 const struct OperationRequest *req)
862{
863 return GNUNET_OK;
864}
865
866
867static void
868handle_client_state_get_prefix (void *cls,
869 const struct OperationRequest *req)
870{
871 struct GNUNET_SERVICE_Client *client = cls;
872
873 struct SendClosure sc = { .op_id = req->op_id, .client = client };
874 int64_t ret = GNUNET_SYSERR;
875 const char *name = (const char *) &req[1];
876 uint16_t name_size = ntohs (req->header.size) - sizeof (*req);
877
878 if (name_size <= 1 || '\0' != name[name_size - 1])
879 {
880 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
881 _("Tried to get invalid state variable name!\n"));
882 GNUNET_break (0);
883 }
884 else
885 {
886 ret = db->state_get_prefix (db->cls, &req->channel_key, name,
887 &send_state_var, &sc);
888 }
889 switch (ret)
890 {
891 case GNUNET_OK:
892 case GNUNET_NO:
893 break;
894 default:
895 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
896 _("Failed to get state variable!\n"));
897 }
898
899 send_result_code (client, req->op_id, ret, NULL);
900 GNUNET_SERVICE_client_continue (client);
901}
902
903
904/**
905 * A new client connected.
906 *
907 * @param cls NULL
908 * @param client client to add
909 * @param mq message queue for @a client
910 * @return @a client
911 */
912static void *
913client_notify_connect (void *cls,
914 struct GNUNET_SERVICE_Client *client,
915 struct GNUNET_MQ_Handle *mq)
916{
917 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client connected: %p\n", client);
918
919 return client;
920}
921
922
923/**
924 * Called whenever a client is disconnected.
925 * Frees our resources associated with that client.
926 *
927 * @param cls closure
928 * @param client identification of the client
929 * @param app_ctx must match @a client
930 */
931static void
932client_notify_disconnect (void *cls,
933 struct GNUNET_SERVICE_Client *client,
934 void *app_ctx)
935{
936}
937
938
939/**
940 * Initialize the PSYCstore service.
941 *
942 * @param cls Closure.
943 * @param server The initialized server.
944 * @param c Configuration to use.
945 */
946static void
947run (void *cls,
948 const struct GNUNET_CONFIGURATION_Handle *c,
949 struct GNUNET_SERVICE_Handle *svc)
950{
951 cfg = c;
952 service = svc;
953
954 /* Loading database plugin */
955 char *database;
956 if (GNUNET_OK !=
957 GNUNET_CONFIGURATION_get_value_string (cfg, "psycstore", "database",
958 &database))
959 {
960 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
961 "psycstore",
962 "database");
963 }
964 else
965 {
966 GNUNET_asprintf (&db_lib_name,
967 "libgnunet_plugin_psycstore_%s",
968 database);
969 db = GNUNET_PLUGIN_load (db_lib_name, (void *) cfg);
970 GNUNET_free (database);
971 }
972 if (NULL == db)
973 {
974 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
975 "Could not load database backend `%s'\n",
976 db_lib_name);
977 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
978 return;
979 }
980
981 stats = GNUNET_STATISTICS_create ("psycstore", cfg);
982 GNUNET_SCHEDULER_add_shutdown (shutdown_task,
983 NULL);
984}
985
986/**
987 * Define "main" method using service macro.
988 */
989GNUNET_SERVICE_MAIN
990("psycstore",
991 GNUNET_SERVICE_OPTION_NONE,
992 run,
993 client_notify_connect,
994 client_notify_disconnect,
995 NULL,
996 GNUNET_MQ_hd_fixed_size (client_membership_store,
997 GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_STORE,
998 struct MembershipStoreRequest,
999 NULL),
1000 GNUNET_MQ_hd_fixed_size (client_membership_test,
1001 GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_TEST,
1002 struct MembershipTestRequest,
1003 NULL),
1004 GNUNET_MQ_hd_var_size (client_fragment_store,
1005 GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_STORE,
1006 struct FragmentStoreRequest,
1007 NULL),
1008 GNUNET_MQ_hd_fixed_size (client_fragment_get,
1009 GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_GET,
1010 struct FragmentGetRequest,
1011 NULL),
1012 GNUNET_MQ_hd_var_size (client_message_get,
1013 GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET,
1014 struct MessageGetRequest,
1015 NULL),
1016 GNUNET_MQ_hd_fixed_size (client_message_get_fragment,
1017 GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET_FRAGMENT,
1018 struct MessageGetFragmentRequest,
1019 NULL),
1020 GNUNET_MQ_hd_fixed_size (client_counters_get,
1021 GNUNET_MESSAGE_TYPE_PSYCSTORE_COUNTERS_GET,
1022 struct OperationRequest,
1023 NULL),
1024 GNUNET_MQ_hd_fixed_size (client_state_modify,
1025 GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_MODIFY,
1026 struct StateModifyRequest,
1027 NULL),
1028 GNUNET_MQ_hd_var_size (client_state_sync,
1029 GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_SYNC,
1030 struct StateSyncRequest,
1031 NULL),
1032 GNUNET_MQ_hd_fixed_size (client_state_reset,
1033 GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_RESET,
1034 struct OperationRequest,
1035 NULL),
1036 GNUNET_MQ_hd_fixed_size (client_state_hash_update,
1037 GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_HASH_UPDATE,
1038 struct StateHashUpdateRequest,
1039 NULL),
1040 GNUNET_MQ_hd_var_size (client_state_get,
1041 GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_GET,
1042 struct OperationRequest,
1043 NULL),
1044 GNUNET_MQ_hd_var_size (client_state_get_prefix,
1045 GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_GET_PREFIX,
1046 struct OperationRequest,
1047 NULL));
1048
1049/* 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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file psycstore/plugin_psycstore_mysql.c
23 * @brief mysql-based psycstore backend
24 * @author Gabor X Toth
25 * @author Christian Grothoff
26 * @author Christophe Genevey
27 */
28
29#include "platform.h"
30#include "gnunet_psycstore_plugin.h"
31#include "gnunet_psycstore_service.h"
32#include "gnunet_multicast_service.h"
33#include "gnunet_crypto_lib.h"
34#include "gnunet_psyc_util_lib.h"
35#include "psycstore.h"
36#include "gnunet_my_lib.h"
37#include "gnunet_mysql_lib.h"
38#include <mysql/mysql.h>
39
40/**
41 * After how many ms "busy" should a DB operation fail for good? A
42 * low value makes sure that we are more responsive to requests
43 * (especially PUTs). A high value guarantees a higher success rate
44 * (SELECTs in iterate can take several seconds despite LIMIT=1).
45 *
46 * The default value of 1s should ensure that users do not experience
47 * huge latencies while at the same time allowing operations to
48 * succeed with reasonable probability.
49 */
50#define BUSY_TIMEOUT_MS 1000
51
52#define DEBUG_PSYCSTORE GNUNET_EXTRA_LOGGING
53
54/**
55 * Log an error message at log-level 'level' that indicates
56 * a failure of the command 'cmd' on file 'filename'
57 * with the message given by strerror(errno).
58 */
59#define LOG_MYSQL(db, level, cmd, stmt) \
60 do { \
61 GNUNET_log_from (level, "psycstore-mysql", \
62 _("`%s' failed at %s:%d with error: %s\n"), \
63 cmd, __FILE__, __LINE__, \
64 mysql_stmt_error (GNUNET_MYSQL_statement_get_stmt(stmt))); \
65 } while (0)
66
67#define LOG(kind,...) GNUNET_log_from (kind, "psycstore-mysql", __VA_ARGS__)
68
69enum Transactions {
70 TRANSACTION_NONE = 0,
71 TRANSACTION_STATE_MODIFY,
72 TRANSACTION_STATE_SYNC,
73};
74
75/**
76 * Context for all functions in this plugin.
77 */
78struct Plugin
79{
80
81 const struct GNUNET_CONFIGURATION_Handle *cfg;
82
83 /**
84 * MySQL context.
85 */
86 struct GNUNET_MYSQL_Context *mc;
87
88 /**
89 * Current transaction.
90 */
91 enum Transactions transaction;
92
93 /**
94 * Precompiled SQL for channel_key_store()
95 */
96 struct GNUNET_MYSQL_StatementHandle *insert_channel_key;
97
98 /**
99 * Precompiled SQL for slave_key_store()
100 */
101 struct GNUNET_MYSQL_StatementHandle *insert_slave_key;
102
103 /**
104 * Precompiled SQL for membership_store()
105 */
106 struct GNUNET_MYSQL_StatementHandle *insert_membership;
107
108 /**
109 * Precompiled SQL for membership_test()
110 */
111 struct GNUNET_MYSQL_StatementHandle *select_membership;
112
113 /**
114 * Precompiled SQL for fragment_store()
115 */
116 struct GNUNET_MYSQL_StatementHandle *insert_fragment;
117
118 /**
119 * Precompiled SQL for message_add_flags()
120 */
121 struct GNUNET_MYSQL_StatementHandle *update_message_flags;
122
123 /**
124 * Precompiled SQL for fragment_get()
125 */
126 struct GNUNET_MYSQL_StatementHandle *select_fragments;
127
128 /**
129 * Precompiled SQL for fragment_get()
130 */
131 struct GNUNET_MYSQL_StatementHandle *select_latest_fragments;
132
133 /**
134 * Precompiled SQL for message_get()
135 */
136 struct GNUNET_MYSQL_StatementHandle *select_messages;
137
138 /**
139 * Precompiled SQL for message_get()
140 */
141 struct GNUNET_MYSQL_StatementHandle *select_latest_messages;
142
143 /**
144 * Precompiled SQL for message_get_fragment()
145 */
146 struct GNUNET_MYSQL_StatementHandle *select_message_fragment;
147
148 /**
149 * Precompiled SQL for counters_get_message()
150 */
151 struct GNUNET_MYSQL_StatementHandle *select_counters_message;
152
153 /**
154 * Precompiled SQL for counters_get_state()
155 */
156 struct GNUNET_MYSQL_StatementHandle *select_counters_state;
157
158 /**
159 * Precompiled SQL for state_modify_end()
160 */
161 struct GNUNET_MYSQL_StatementHandle *update_state_hash_message_id;
162
163 /**
164 * Precompiled SQL for state_sync_end()
165 */
166 struct GNUNET_MYSQL_StatementHandle *update_max_state_message_id;
167
168 /**
169 * Precompiled SQL for state_modify_op()
170 */
171 struct GNUNET_MYSQL_StatementHandle *insert_state_current;
172
173 /**
174 * Precompiled SQL for state_modify_end()
175 */
176 struct GNUNET_MYSQL_StatementHandle *delete_state_empty;
177
178 /**
179 * Precompiled SQL for state_set_signed()
180 */
181 struct GNUNET_MYSQL_StatementHandle *update_state_signed;
182
183 /**
184 * Precompiled SQL for state_sync()
185 */
186 struct GNUNET_MYSQL_StatementHandle *insert_state_sync;
187
188 /**
189 * Precompiled SQL for state_sync()
190 */
191 struct GNUNET_MYSQL_StatementHandle *delete_state;
192
193 /**
194 * Precompiled SQL for state_sync()
195 */
196 struct GNUNET_MYSQL_StatementHandle *insert_state_from_sync;
197
198 /**
199 * Precompiled SQL for state_sync()
200 */
201 struct GNUNET_MYSQL_StatementHandle *delete_state_sync;
202
203 /**
204 * Precompiled SQL for state_get_signed()
205 */
206 struct GNUNET_MYSQL_StatementHandle *select_state_signed;
207
208 /**
209 * Precompiled SQL for state_get()
210 */
211 struct GNUNET_MYSQL_StatementHandle *select_state_one;
212
213 /**
214 * Precompiled SQL for state_get_prefix()
215 */
216 struct GNUNET_MYSQL_StatementHandle *select_state_prefix;
217
218};
219
220#if DEBUG_PSYCSTORE
221
222static void
223mysql_trace (void *cls, const char *sql)
224{
225 LOG(GNUNET_ERROR_TYPE_DEBUG, "MYSQL query:\n%s\n", sql);
226}
227
228#endif
229
230
231/**
232 * @brief Prepare a SQL statement
233 *
234 * @param dbh handle to the database
235 * @param sql SQL statement, UTF-8 encoded
236 * @param stmt set to the prepared statement
237 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
238 */
239static int
240mysql_prepare (struct GNUNET_MYSQL_Context *mc,
241 const char *sql,
242 struct GNUNET_MYSQL_StatementHandle **stmt)
243{
244 *stmt = GNUNET_MYSQL_statement_prepare (mc,
245 sql);
246
247 if (NULL == *stmt)
248 {
249 LOG (GNUNET_ERROR_TYPE_ERROR,
250 _("Error preparing SQL query: %s\n %s\n"),
251 mysql_stmt_error (GNUNET_MYSQL_statement_get_stmt (*stmt)),
252 sql);
253 return GNUNET_SYSERR;
254 }
255 LOG (GNUNET_ERROR_TYPE_DEBUG,
256 "Prepared `%s' / %p\n",
257 sql,
258 stmt);
259 return GNUNET_OK;
260}
261
262
263/**
264 * Initialize the database connections and associated
265 * data structures (create tables and indices
266 * as needed as well).
267 *
268 * @param plugin the plugin context (state for this module)
269 * @return #GNUNET_OK on success
270 */
271static int
272database_setup (struct Plugin *plugin)
273{
274 /* Open database and precompile statements */
275 plugin->mc = GNUNET_MYSQL_context_create (plugin->cfg,
276 "psycstore-mysql");
277
278 if (NULL == plugin->mc)
279 {
280 LOG (GNUNET_ERROR_TYPE_ERROR,
281 _("Unable to initialize Mysql.\n"));
282 return GNUNET_SYSERR;
283 }
284
285#define STMT_RUN(sql) \
286 if (GNUNET_OK != \
287 GNUNET_MYSQL_statement_run (plugin->mc, \
288 sql)) \
289 { \
290 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, \
291 _("Failed to run SQL statement `%s'\n"), \
292 sql); \
293 return GNUNET_SYSERR; \
294 }
295
296 /* Create tables */
297 STMT_RUN ("CREATE TABLE IF NOT EXISTS channels (\n"
298 " id BIGINT UNSIGNED AUTO_INCREMENT,\n"
299 " pub_key BLOB(32),\n"
300 " max_state_message_id BIGINT UNSIGNED,\n"
301 " state_hash_message_id BIGINT UNSIGNED,\n"
302 " PRIMARY KEY(id),\n"
303 " UNIQUE KEY(pub_key(32))\n"
304 ");");
305
306 STMT_RUN ("CREATE TABLE IF NOT EXISTS slaves (\n"
307 " id BIGINT UNSIGNED AUTO_INCREMENT,\n"
308 " pub_key BLOB(32),\n"
309 " PRIMARY KEY(id),\n"
310 " UNIQUE KEY(pub_key(32))\n"
311 ");");
312
313 STMT_RUN ("CREATE TABLE IF NOT EXISTS membership (\n"
314 " channel_id BIGINT UNSIGNED NOT NULL REFERENCES channels(id),\n"
315 " slave_id BIGINT UNSIGNED NOT NULL REFERENCES slaves(id),\n"
316 " did_join TINYINT NOT NULL,\n"
317 " announced_at BIGINT UNSIGNED NOT NULL,\n"
318 " effective_since BIGINT UNSIGNED NOT NULL,\n"
319 " group_generation BIGINT UNSIGNED NOT NULL\n"
320 ");");
321
322/*** FIX because IF NOT EXISTS doesn't work ***/
323 GNUNET_MYSQL_statement_run (plugin->mc,
324 "CREATE INDEX idx_membership_channel_id_slave_id "
325 "ON membership (channel_id, slave_id);");
326
327 /** @todo messages table: add method_name column */
328 STMT_RUN ("CREATE TABLE IF NOT EXISTS messages (\n"
329 " channel_id BIGINT UNSIGNED NOT NULL REFERENCES channels(id),\n"
330 " hop_counter BIGINT UNSIGNED NOT NULL,\n"
331 " signature BLOB,\n"
332 " purpose BLOB,\n"
333 " fragment_id BIGINT UNSIGNED NOT NULL,\n"
334 " fragment_offset BIGINT UNSIGNED NOT NULL,\n"
335 " message_id BIGINT UNSIGNED NOT NULL,\n"
336 " group_generation BIGINT UNSIGNED NOT NULL,\n"
337 " multicast_flags BIGINT UNSIGNED NOT NULL,\n"
338 " psycstore_flags BIGINT UNSIGNED NOT NULL,\n"
339 " data BLOB,\n"
340 " PRIMARY KEY (channel_id, fragment_id),\n"
341 " UNIQUE KEY(channel_id, message_id, fragment_offset)\n"
342 ");");
343
344 STMT_RUN ("CREATE TABLE IF NOT EXISTS state (\n"
345 " channel_id BIGINT UNSIGNED NOT NULL REFERENCES channels(id),\n"
346 " name TEXT NOT NULL,\n"
347 " value_current BLOB,\n"
348 " value_signed BLOB\n"
349 //" PRIMARY KEY (channel_id, name(255))\n"
350 ");");
351
352 STMT_RUN ("CREATE TABLE IF NOT EXISTS state_sync (\n"
353 " channel_id BIGINT UNSIGNED NOT NULL REFERENCES channels(id),\n"
354 " name TEXT NOT NULL,\n"
355 " value BLOB\n"
356 //" PRIMARY KEY (channel_id, name(255))\n"
357 ");");
358#undef STMT_RUN
359
360 /* Prepare statements */
361#define PREP(stmt,handle) \
362 if (GNUNET_OK != mysql_prepare (plugin->mc, stmt, handle)) \
363 { \
364 GNUNET_break (0); \
365 return GNUNET_SYSERR; \
366 }
367 PREP ("INSERT IGNORE INTO channels (pub_key) VALUES (?);",
368 &plugin->insert_channel_key);
369 PREP ("INSERT IGNORE INTO slaves (pub_key) VALUES (?);",
370 &plugin->insert_slave_key);
371 PREP ("INSERT INTO membership\n"
372 " (channel_id, slave_id, did_join, announced_at,\n"
373 " effective_since, group_generation)\n"
374 "VALUES ((SELECT id FROM channels WHERE pub_key = ?),\n"
375 " (SELECT id FROM slaves WHERE pub_key = ?),\n"
376 " ?, ?, ?, ?);",
377 &plugin->insert_membership);
378 PREP ("SELECT did_join FROM membership\n"
379 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
380 " AND slave_id = (SELECT id FROM slaves WHERE pub_key = ?)\n"
381 " AND effective_since <= ? AND did_join = 1\n"
382 "ORDER BY announced_at DESC LIMIT 1;",
383 &plugin->select_membership);
384
385 PREP ("INSERT IGNORE INTO messages\n"
386 " (channel_id, hop_counter, signature, purpose,\n"
387 " fragment_id, fragment_offset, message_id,\n"
388 " group_generation, multicast_flags, psycstore_flags, data)\n"
389 "VALUES ((SELECT id FROM channels WHERE pub_key = ?),\n"
390 " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);",
391 &plugin->insert_fragment);
392
393 PREP ("UPDATE messages\n"
394 "SET psycstore_flags = psycstore_flags | ?\n"
395 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
396 " AND message_id = ? AND fragment_offset = 0;",
397 &plugin->update_message_flags);
398
399 PREP ("SELECT hop_counter, signature, purpose, fragment_id,\n"
400 " fragment_offset, message_id, group_generation,\n"
401 " multicast_flags, psycstore_flags, data\n"
402 "FROM messages\n"
403 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
404 " AND ? <= fragment_id AND fragment_id <= ? LIMIT 1;",
405 &plugin->select_fragments);
406
407 /** @todo select_messages: add method_prefix filter */
408 PREP ("SELECT hop_counter, signature, purpose, fragment_id,\n"
409 " fragment_offset, message_id, group_generation,\n"
410 " multicast_flags, psycstore_flags, data\n"
411 "FROM messages\n"
412 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
413 " AND ? <= message_id AND message_id <= ?\n"
414 "LIMIT ?;",
415 &plugin->select_messages);
416
417 PREP ("SELECT * FROM\n"
418 "(SELECT hop_counter, signature, purpose, fragment_id,\n"
419 " fragment_offset, message_id, group_generation,\n"
420 " multicast_flags, psycstore_flags, data\n"
421 " FROM messages\n"
422 " WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
423 " ORDER BY fragment_id DESC\n"
424 " LIMIT ?)\n"
425 "ORDER BY fragment_id;",
426 &plugin->select_latest_fragments);
427
428 /** @todo select_latest_messages: add method_prefix filter */
429 PREP ("SELECT hop_counter, signature, purpose, fragment_id,\n"
430 " fragment_offset, message_id, group_generation,\n"
431 " multicast_flags, psycstore_flags, data\n"
432 "FROM messages\n"
433 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
434 " AND message_id IN\n"
435 " (SELECT message_id\n"
436 " FROM messages\n"
437 " WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
438 " GROUP BY message_id\n"
439 " ORDER BY message_id\n"
440 " DESC LIMIT ?)\n"
441 "ORDER BY fragment_id;",
442 &plugin->select_latest_messages);
443
444 PREP ("SELECT hop_counter, signature, purpose, fragment_id,\n"
445 " fragment_offset, message_id, group_generation,\n"
446 " multicast_flags, psycstore_flags, data\n"
447 "FROM messages\n"
448 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
449 " AND message_id = ? AND fragment_offset = ?;",
450 &plugin->select_message_fragment);
451
452 PREP ("SELECT fragment_id, message_id, group_generation\n"
453 "FROM messages\n"
454 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
455 "ORDER BY fragment_id DESC LIMIT 1;",
456 &plugin->select_counters_message);
457
458 PREP ("SELECT max_state_message_id\n"
459 "FROM channels\n"
460 "WHERE pub_key = ? AND max_state_message_id IS NOT NULL;",
461 &plugin->select_counters_state);
462
463 PREP ("UPDATE channels\n"
464 "SET max_state_message_id = ?\n"
465 "WHERE pub_key = ?;",
466 &plugin->update_max_state_message_id);
467
468 PREP ("UPDATE channels\n"
469 "SET state_hash_message_id = ?\n"
470 "WHERE pub_key = ?;",
471 &plugin->update_state_hash_message_id);
472
473 PREP ("REPLACE INTO state\n"
474 " (channel_id, name, value_current, value_signed)\n"
475 "SELECT new.channel_id, new.name, new.value_current, old.value_signed\n"
476 "FROM (SELECT (SELECT id FROM channels WHERE pub_key = ?) AS channel_id,\n"
477 " (SELECT ?) AS name,\n"
478 " (SELECT ?) AS value_current\n"
479 " ) AS new\n"
480 "LEFT JOIN (SELECT channel_id, name, value_signed\n"
481 " FROM state) AS old\n"
482 "ON new.channel_id = old.channel_id AND new.name = old.name;",
483 &plugin->insert_state_current);
484
485 PREP ("DELETE FROM state\n"
486 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
487 " AND (value_current IS NULL OR length(value_current) = 0)\n"
488 " AND (value_signed IS NULL OR length(value_signed) = 0);",
489 &plugin->delete_state_empty);
490
491 PREP ("UPDATE state\n"
492 "SET value_signed = value_current\n"
493 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);",
494 &plugin->update_state_signed);
495
496 PREP ("DELETE FROM state\n"
497 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);",
498 &plugin->delete_state);
499
500 PREP ("INSERT INTO state_sync (channel_id, name, value)\n"
501 "VALUES ((SELECT id FROM channels WHERE pub_key = ?), ?, ?);",
502 &plugin->insert_state_sync);
503
504 PREP ("INSERT INTO state\n"
505 " (channel_id, name, value_current, value_signed)\n"
506 "SELECT channel_id, name, value, value\n"
507 "FROM state_sync\n"
508 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);",
509 &plugin->insert_state_from_sync);
510
511 PREP ("DELETE FROM state_sync\n"
512 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);",
513 &plugin->delete_state_sync);
514
515 PREP ("SELECT value_current\n"
516 "FROM state\n"
517 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
518 " AND name = ?;",
519 &plugin->select_state_one);
520
521 PREP ("SELECT name, value_current\n"
522 "FROM state\n"
523 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
524 " AND (name = ? OR substr(name, 1, ?) = ?);",
525 &plugin->select_state_prefix);
526
527 PREP ("SELECT name, value_signed\n"
528 "FROM state\n"
529 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)"
530 " AND value_signed IS NOT NULL;",
531 &plugin->select_state_signed);
532#undef PREP
533
534 return GNUNET_OK;
535}
536
537
538/**
539 * Shutdown database connection and associate data
540 * structures.
541 * @param plugin the plugin context (state for this module)
542 */
543static void
544database_shutdown (struct Plugin *plugin)
545{
546 GNUNET_MYSQL_context_destroy (plugin->mc);
547}
548
549
550/**
551 * Execute a prepared statement with a @a channel_key argument.
552 *
553 * @param plugin Plugin handle.
554 * @param stmt Statement to execute.
555 * @param channel_key Public key of the channel.
556 *
557 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
558 */
559static int
560exec_channel (struct Plugin *plugin, struct GNUNET_MYSQL_StatementHandle *stmt,
561 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
562{
563 struct GNUNET_MY_QueryParam params[] = {
564 GNUNET_MY_query_param_auto_from_type (channel_key),
565 GNUNET_MY_query_param_end
566 };
567
568 if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params))
569 {
570 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
571 "mysql exec_channel", stmt);
572 }
573
574 if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
575 {
576 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
577 "mysql_stmt_reset", stmt);
578 return GNUNET_SYSERR;
579 }
580
581 return GNUNET_OK;
582}
583
584
585/**
586 * Begin a transaction.
587 */
588static int
589transaction_begin (struct Plugin *plugin, enum Transactions transaction)
590{
591 if (GNUNET_OK != GNUNET_MYSQL_statement_run (plugin->mc, "BEGIN"))
592 {
593 LOG(GNUNET_ERROR_TYPE_ERROR, "transaction_begin failed");
594 return GNUNET_SYSERR;
595 }
596
597 plugin->transaction = transaction;
598 return GNUNET_OK;
599}
600
601
602/**
603 * Commit current transaction.
604 */
605static int
606transaction_commit (struct Plugin *plugin)
607{
608 if (GNUNET_OK != GNUNET_MYSQL_statement_run (plugin->mc, "COMMIT"))
609 {
610 LOG(GNUNET_ERROR_TYPE_ERROR, "transaction_commit failed");
611 return GNUNET_SYSERR;
612 }
613
614 plugin->transaction = TRANSACTION_NONE;
615 return GNUNET_OK;
616}
617
618
619/**
620 * Roll back current transaction.
621 */
622static int
623transaction_rollback (struct Plugin *plugin)
624{
625 if (GNUNET_OK != GNUNET_MYSQL_statement_run (plugin->mc, "ROLLBACK"))
626 {
627 LOG(GNUNET_ERROR_TYPE_ERROR, "transaction_rollback failed");
628 return GNUNET_SYSERR;
629 }
630
631 plugin->transaction = TRANSACTION_NONE;
632 return GNUNET_OK;
633}
634
635
636static int
637channel_key_store (struct Plugin *plugin,
638 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
639{
640 struct GNUNET_MYSQL_StatementHandle *stmt = plugin->insert_channel_key;
641
642 struct GNUNET_MY_QueryParam params[] = {
643 GNUNET_MY_query_param_auto_from_type (channel_key),
644 GNUNET_MY_query_param_end
645 };
646
647 if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params))
648 {
649 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
650 "mysql exec_prepared", stmt);
651 return GNUNET_SYSERR;
652 }
653
654 if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
655 {
656 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
657 "mysql_stmt_reset", stmt);
658 return GNUNET_SYSERR;
659 }
660
661 return GNUNET_OK;
662}
663
664
665static int
666slave_key_store (struct Plugin *plugin,
667 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key)
668{
669 struct GNUNET_MYSQL_StatementHandle *stmt = plugin->insert_slave_key;
670
671 struct GNUNET_MY_QueryParam params[] = {
672 GNUNET_MY_query_param_auto_from_type (slave_key),
673 GNUNET_MY_query_param_end
674 };
675
676 if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params))
677 {
678 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
679 "mysql exec_prepared", stmt);
680 return GNUNET_SYSERR;
681 }
682
683 if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
684 {
685 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
686 "mysql_stmt_reset", stmt);
687 return GNUNET_SYSERR;
688 }
689
690 return GNUNET_OK;
691}
692
693
694/**
695 * Store join/leave events for a PSYC channel in order to be able to answer
696 * membership test queries later.
697 *
698 * @see GNUNET_PSYCSTORE_membership_store()
699 *
700 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
701 */
702static int
703mysql_membership_store (void *cls,
704 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
705 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
706 int did_join,
707 uint64_t announced_at,
708 uint64_t effective_since,
709 uint64_t group_generation)
710{
711 struct Plugin *plugin = cls;
712
713 uint32_t idid_join = (uint32_t)did_join;
714
715 struct GNUNET_MYSQL_StatementHandle *stmt = plugin->insert_membership;
716
717 GNUNET_assert (TRANSACTION_NONE == plugin->transaction);
718
719 if (announced_at > INT64_MAX ||
720 effective_since > INT64_MAX ||
721 group_generation > INT64_MAX)
722 {
723 GNUNET_break (0);
724 return GNUNET_SYSERR;
725 }
726
727 if (GNUNET_OK != channel_key_store (plugin, channel_key)
728 || GNUNET_OK != slave_key_store (plugin, slave_key))
729 return GNUNET_SYSERR;
730
731 struct GNUNET_MY_QueryParam params[] = {
732 GNUNET_MY_query_param_auto_from_type (channel_key),
733 GNUNET_MY_query_param_auto_from_type (slave_key),
734 GNUNET_MY_query_param_uint32 (&idid_join),
735 GNUNET_MY_query_param_uint64 (&announced_at),
736 GNUNET_MY_query_param_uint64 (&effective_since),
737 GNUNET_MY_query_param_uint64 (&group_generation),
738 GNUNET_MY_query_param_end
739 };
740
741 if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params))
742 {
743 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
744 "mysql exec_prepared", stmt);
745 return GNUNET_SYSERR;
746 }
747
748 if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
749 {
750 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
751 "mysql_stmt_reset", stmt);
752 return GNUNET_SYSERR;
753 }
754 return GNUNET_OK;
755}
756
757/**
758 * Test if a member was admitted to the channel at the given message ID.
759 *
760 * @see GNUNET_PSYCSTORE_membership_test()
761 *
762 * @return #GNUNET_YES if the member was admitted, #GNUNET_NO if not,
763 * #GNUNET_SYSERR if there was en error.
764 */
765static int
766membership_test (void *cls,
767 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
768 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
769 uint64_t message_id)
770{
771 struct Plugin *plugin = cls;
772
773 struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_membership;
774
775 uint32_t did_join = 0;
776
777 int ret = GNUNET_SYSERR;
778
779 struct GNUNET_MY_QueryParam params_select[] = {
780 GNUNET_MY_query_param_auto_from_type (channel_key),
781 GNUNET_MY_query_param_auto_from_type (slave_key),
782 GNUNET_MY_query_param_uint64 (&message_id),
783 GNUNET_MY_query_param_end
784 };
785
786 if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select))
787 {
788 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
789 "mysql execute prepared", stmt);
790 return GNUNET_SYSERR;
791 }
792
793 struct GNUNET_MY_ResultSpec results_select[] = {
794 GNUNET_MY_result_spec_uint32 (&did_join),
795 GNUNET_MY_result_spec_end
796 };
797
798 switch (GNUNET_MY_extract_result (stmt, results_select))
799 {
800 case GNUNET_NO:
801 ret = GNUNET_NO;
802 break;
803 case GNUNET_OK:
804 ret = GNUNET_YES;
805 break;
806 default:
807 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
808 "mysql extract_result", stmt);
809 return GNUNET_SYSERR;
810 }
811
812 if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
813 {
814 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
815 "mysql_stmt_reset", stmt);
816 return GNUNET_SYSERR;
817 }
818
819 return ret;
820}
821
822/**
823 * Store a message fragment sent to a channel.
824 *
825 * @see GNUNET_PSYCSTORE_fragment_store()
826 *
827 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
828 */
829static int
830fragment_store (void *cls,
831 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
832 const struct GNUNET_MULTICAST_MessageHeader *msg,
833 uint32_t psycstore_flags)
834{
835 struct Plugin *plugin = cls;
836
837 struct GNUNET_MYSQL_StatementHandle *stmt = plugin->insert_fragment;
838
839 GNUNET_assert (TRANSACTION_NONE == plugin->transaction);
840
841 uint64_t fragment_id = GNUNET_ntohll (msg->fragment_id);
842
843 uint64_t fragment_offset = GNUNET_ntohll (msg->fragment_offset);
844 uint64_t message_id = GNUNET_ntohll (msg->message_id);
845 uint64_t group_generation = GNUNET_ntohll (msg->group_generation);
846
847 uint64_t hop_counter = ntohl(msg->hop_counter);
848 uint64_t flags = ntohl(msg->flags);
849
850 if (fragment_id > INT64_MAX || fragment_offset > INT64_MAX ||
851 message_id > INT64_MAX || group_generation > INT64_MAX)
852 {
853 LOG(GNUNET_ERROR_TYPE_ERROR,
854 "Tried to store fragment with a field > INT64_MAX: "
855 "%lu, %lu, %lu, %lu\n", fragment_id, fragment_offset,
856 message_id, group_generation);
857 GNUNET_break (0);
858 return GNUNET_SYSERR;
859 }
860
861 if (GNUNET_OK != channel_key_store (plugin, channel_key))
862 return GNUNET_SYSERR;
863
864 struct GNUNET_MY_QueryParam params_insert[] = {
865 GNUNET_MY_query_param_auto_from_type (channel_key),
866 GNUNET_MY_query_param_uint64 (&hop_counter),
867 GNUNET_MY_query_param_auto_from_type (&msg->signature),
868 GNUNET_MY_query_param_auto_from_type (&msg->purpose),
869 GNUNET_MY_query_param_uint64 (&fragment_id),
870 GNUNET_MY_query_param_uint64 (&fragment_offset),
871 GNUNET_MY_query_param_uint64 (&message_id),
872 GNUNET_MY_query_param_uint64 (&group_generation),
873 GNUNET_MY_query_param_uint64 (&flags),
874 GNUNET_MY_query_param_uint32 (&psycstore_flags),
875 GNUNET_MY_query_param_fixed_size (&msg[1], ntohs (msg->header.size)
876 - sizeof (*msg)),
877 GNUNET_MY_query_param_end
878 };
879
880 if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_insert))
881 {
882 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
883 "mysql execute prepared", stmt);
884 return GNUNET_SYSERR;
885 }
886
887 if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
888 {
889 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
890 "mysql_stmt_reset", stmt);
891 return GNUNET_SYSERR;
892 }
893
894 return GNUNET_OK;
895}
896
897/**
898 * Set additional flags for a given message.
899 *
900 * They are OR'd with any existing flags set.
901 *
902 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
903 */
904static int
905message_add_flags (void *cls,
906 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
907 uint64_t message_id,
908 uint32_t psycstore_flags)
909{
910 struct Plugin *plugin = cls;
911 struct GNUNET_MYSQL_StatementHandle *stmt = plugin->update_message_flags;
912
913 int sql_ret;
914 int ret = GNUNET_SYSERR;
915
916 struct GNUNET_MY_QueryParam params_update[] = {
917 GNUNET_MY_query_param_uint32 (&psycstore_flags),
918 GNUNET_MY_query_param_auto_from_type (channel_key),
919 GNUNET_MY_query_param_uint64 (&message_id),
920 GNUNET_MY_query_param_end
921 };
922
923 sql_ret = GNUNET_MY_exec_prepared (plugin->mc, stmt, params_update);
924 switch (sql_ret)
925 {
926 case GNUNET_OK:
927 ret = GNUNET_OK;
928 break;
929
930 default:
931 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
932 "mysql execute prepared", stmt);
933 }
934
935 if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
936 {
937 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
938 "mysql_stmt_reset", stmt);
939 return GNUNET_SYSERR;
940 }
941
942 return ret;
943}
944
945
946static int
947fragment_row (struct GNUNET_MYSQL_StatementHandle *stmt,
948 GNUNET_PSYCSTORE_FragmentCallback cb,
949 void *cb_cls,
950 uint64_t *returned_fragments)
951{
952
953 uint32_t hop_counter;
954 void *signature = NULL;
955 void *purpose = NULL;
956 size_t signature_size;
957 size_t purpose_size;
958 uint64_t fragment_id;
959 uint64_t fragment_offset;
960 uint64_t message_id;
961 uint64_t group_generation;
962 uint64_t flags;
963 void *buf;
964 size_t buf_size;
965 int ret = GNUNET_SYSERR;
966 int sql_ret;
967 struct GNUNET_MULTICAST_MessageHeader *mp;
968 uint64_t msg_flags;
969 struct GNUNET_MY_ResultSpec results[] = {
970 GNUNET_MY_result_spec_uint32 (&hop_counter),
971 GNUNET_MY_result_spec_variable_size (&signature, &signature_size),
972 GNUNET_MY_result_spec_variable_size (&purpose, &purpose_size),
973 GNUNET_MY_result_spec_uint64 (&fragment_id),
974 GNUNET_MY_result_spec_uint64 (&fragment_offset),
975 GNUNET_MY_result_spec_uint64 (&message_id),
976 GNUNET_MY_result_spec_uint64 (&group_generation),
977 GNUNET_MY_result_spec_uint64 (&msg_flags),
978 GNUNET_MY_result_spec_uint64 (&flags),
979 GNUNET_MY_result_spec_variable_size (&buf,
980 &buf_size),
981 GNUNET_MY_result_spec_end
982 };
983
984 do
985 {
986 sql_ret = GNUNET_MY_extract_result (stmt, results);
987 switch (sql_ret)
988 {
989 case GNUNET_NO:
990 if (ret != GNUNET_YES)
991 ret = GNUNET_NO;
992 break;
993
994 case GNUNET_YES:
995 mp = GNUNET_malloc (sizeof (*mp) + buf_size);
996
997 mp->header.size = htons (sizeof (*mp) + buf_size);
998 mp->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE);
999 mp->hop_counter = htonl (hop_counter);
1000 GNUNET_memcpy (&mp->signature,
1001 signature,
1002 signature_size);
1003 GNUNET_memcpy (&mp->purpose,
1004 purpose,
1005 purpose_size);
1006 mp->fragment_id = GNUNET_htonll (fragment_id);
1007 mp->fragment_offset = GNUNET_htonll (fragment_offset);
1008 mp->message_id = GNUNET_htonll (message_id);
1009 mp->group_generation = GNUNET_htonll (group_generation);
1010 mp->flags = htonl(msg_flags);
1011
1012 GNUNET_memcpy (&mp[1],
1013 buf,
1014 buf_size);
1015 ret = cb (cb_cls, mp, (enum GNUNET_PSYCSTORE_MessageFlags) flags);
1016 if (NULL != returned_fragments)
1017 (*returned_fragments)++;
1018 GNUNET_MY_cleanup_result (results);
1019 break;
1020
1021 default:
1022 LOG_MYSQL (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1023 "mysql extract_result", stmt);
1024 }
1025 }
1026 while (GNUNET_YES == sql_ret);
1027
1028 // for debugging
1029 if (GNUNET_NO == ret)
1030 GNUNET_log (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
1031 "Empty result set\n");
1032
1033 return ret;
1034}
1035
1036
1037static int
1038fragment_select (struct Plugin *plugin,
1039 struct GNUNET_MYSQL_StatementHandle *stmt,
1040 struct GNUNET_MY_QueryParam *params,
1041 uint64_t *returned_fragments,
1042 GNUNET_PSYCSTORE_FragmentCallback cb,
1043 void *cb_cls)
1044{
1045 int ret = GNUNET_SYSERR;
1046 int sql_ret;
1047
1048 sql_ret = GNUNET_MY_exec_prepared (plugin->mc, stmt, params);
1049 switch (sql_ret)
1050 {
1051 case GNUNET_NO:
1052 if (ret != GNUNET_YES)
1053 ret = GNUNET_NO;
1054 break;
1055
1056 case GNUNET_YES:
1057 ret = fragment_row (stmt, cb, cb_cls, returned_fragments);
1058 break;
1059
1060 default:
1061 LOG_MYSQL (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1062 "mysql exec_prepared", stmt);
1063 }
1064 return ret;
1065}
1066
1067
1068/**
1069 * Retrieve a message fragment range by fragment ID.
1070 *
1071 * @see GNUNET_PSYCSTORE_fragment_get()
1072 *
1073 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1074 */
1075static int
1076fragment_get (void *cls,
1077 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1078 uint64_t first_fragment_id,
1079 uint64_t last_fragment_id,
1080 uint64_t *returned_fragments,
1081 GNUNET_PSYCSTORE_FragmentCallback cb,
1082 void *cb_cls)
1083{
1084 struct Plugin *plugin = cls;
1085 struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_fragments;
1086 int ret = GNUNET_SYSERR;
1087 struct GNUNET_MY_QueryParam params_select[] = {
1088 GNUNET_MY_query_param_auto_from_type (channel_key),
1089 GNUNET_MY_query_param_uint64 (&first_fragment_id),
1090 GNUNET_MY_query_param_uint64 (&last_fragment_id),
1091 GNUNET_MY_query_param_end
1092 };
1093
1094 *returned_fragments = 0;
1095 ret = fragment_select (plugin, stmt, params_select, returned_fragments, cb, cb_cls);
1096
1097 if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
1098 {
1099 LOG_MYSQL (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1100 "mysql_stmt_reset", stmt);
1101 return GNUNET_SYSERR;
1102 }
1103
1104 return ret;
1105}
1106
1107
1108/**
1109 * Retrieve a message fragment range by fragment ID.
1110 *
1111 * @see GNUNET_PSYCSTORE_fragment_get_latest()
1112 *
1113 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1114 */
1115static int
1116fragment_get_latest (void *cls,
1117 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1118 uint64_t fragment_limit,
1119 uint64_t *returned_fragments,
1120 GNUNET_PSYCSTORE_FragmentCallback cb,
1121 void *cb_cls)
1122{
1123 struct Plugin *plugin = cls;
1124
1125 struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_latest_fragments;
1126
1127 int ret = GNUNET_SYSERR;
1128 *returned_fragments = 0;
1129
1130 struct GNUNET_MY_QueryParam params_select[] = {
1131 GNUNET_MY_query_param_auto_from_type (channel_key),
1132 GNUNET_MY_query_param_uint64 (&fragment_limit),
1133 GNUNET_MY_query_param_end
1134 };
1135
1136 ret = fragment_select (plugin, stmt, params_select, returned_fragments, cb, cb_cls);
1137
1138 if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
1139 {
1140 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1141 "mysql_stmt_reset", stmt);
1142 return GNUNET_SYSERR;
1143 }
1144
1145 return ret;
1146}
1147
1148
1149/**
1150 * Retrieve all fragments of a message ID range.
1151 *
1152 * @see GNUNET_PSYCSTORE_message_get()
1153 *
1154 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1155 */
1156static int
1157message_get (void *cls,
1158 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1159 uint64_t first_message_id,
1160 uint64_t last_message_id,
1161 uint64_t fragment_limit,
1162 uint64_t *returned_fragments,
1163 GNUNET_PSYCSTORE_FragmentCallback cb,
1164 void *cb_cls)
1165{
1166 struct Plugin *plugin = cls;
1167 struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_messages;
1168 int ret;
1169
1170 if (0 == fragment_limit)
1171 fragment_limit = UINT64_MAX;
1172
1173 struct GNUNET_MY_QueryParam params_select[] = {
1174 GNUNET_MY_query_param_auto_from_type (channel_key),
1175 GNUNET_MY_query_param_uint64 (&first_message_id),
1176 GNUNET_MY_query_param_uint64 (&last_message_id),
1177 GNUNET_MY_query_param_uint64 (&fragment_limit),
1178 GNUNET_MY_query_param_end
1179 };
1180
1181 *returned_fragments = 0;
1182 ret = fragment_select (plugin, stmt, params_select, returned_fragments, cb, cb_cls);
1183
1184 if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
1185 {
1186 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1187 "mysql_stmt_reset", stmt);
1188 return GNUNET_SYSERR;
1189 }
1190
1191 return ret;
1192}
1193
1194
1195/**
1196 * Retrieve all fragments of the latest messages.
1197 *
1198 * @see GNUNET_PSYCSTORE_message_get_latest()
1199 *
1200 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1201 */
1202static int
1203message_get_latest (void *cls,
1204 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1205 uint64_t message_limit,
1206 uint64_t *returned_fragments,
1207 GNUNET_PSYCSTORE_FragmentCallback cb,
1208 void *cb_cls)
1209{
1210 struct Plugin *plugin = cls;
1211
1212 struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_latest_messages;
1213
1214 int ret = GNUNET_SYSERR;
1215 *returned_fragments = 0;
1216
1217 struct GNUNET_MY_QueryParam params_select[] = {
1218 GNUNET_MY_query_param_auto_from_type (channel_key),
1219 GNUNET_MY_query_param_auto_from_type (channel_key),
1220 GNUNET_MY_query_param_uint64 (&message_limit),
1221 GNUNET_MY_query_param_end
1222 };
1223
1224 ret = fragment_select (plugin, stmt, params_select, returned_fragments, cb, cb_cls);
1225
1226 if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
1227 {
1228 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1229 "mysql_stmt_reset", stmt);
1230 return GNUNET_SYSERR;
1231 }
1232
1233 return ret;
1234}
1235
1236
1237/**
1238 * Retrieve a fragment of message specified by its message ID and fragment
1239 * offset.
1240 *
1241 * @see GNUNET_PSYCSTORE_message_get_fragment()
1242 *
1243 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1244 */
1245static int
1246message_get_fragment (void *cls,
1247 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1248 uint64_t message_id,
1249 uint64_t fragment_offset,
1250 GNUNET_PSYCSTORE_FragmentCallback cb,
1251 void *cb_cls)
1252{
1253 struct Plugin *plugin = cls;
1254 struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_message_fragment;
1255 int sql_ret;
1256 int ret = GNUNET_SYSERR;
1257
1258 struct GNUNET_MY_QueryParam params_select[] = {
1259 GNUNET_MY_query_param_auto_from_type (channel_key),
1260 GNUNET_MY_query_param_uint64 (&message_id),
1261 GNUNET_MY_query_param_uint64 (&fragment_offset),
1262 GNUNET_MY_query_param_end
1263 };
1264
1265 sql_ret = GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select);
1266 switch (sql_ret)
1267 {
1268 case GNUNET_NO:
1269 ret = GNUNET_NO;
1270 break;
1271
1272 case GNUNET_OK:
1273 ret = fragment_row (stmt, cb, cb_cls, NULL);
1274 break;
1275
1276 default:
1277 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1278 "mysql execute prepared", stmt);
1279 }
1280
1281 if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
1282 {
1283 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1284 "mysql_stmt_reset", stmt);
1285 return GNUNET_SYSERR;
1286 }
1287
1288 return ret;
1289}
1290
1291/**
1292 * Retrieve the max. values of message counters for a channel.
1293 *
1294 * @see GNUNET_PSYCSTORE_counters_get()
1295 *
1296 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1297 */
1298static int
1299counters_message_get (void *cls,
1300 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1301 uint64_t *max_fragment_id,
1302 uint64_t *max_message_id,
1303 uint64_t *max_group_generation)
1304{
1305 struct Plugin *plugin = cls;
1306
1307 struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_counters_message;
1308
1309 int ret = GNUNET_SYSERR;
1310
1311 struct GNUNET_MY_QueryParam params_select[] = {
1312 GNUNET_MY_query_param_auto_from_type (channel_key),
1313 GNUNET_MY_query_param_end
1314 };
1315
1316 if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select))
1317 {
1318 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1319 "mysql execute prepared", stmt);
1320 return GNUNET_SYSERR;
1321 }
1322
1323 struct GNUNET_MY_ResultSpec results_select[] = {
1324 GNUNET_MY_result_spec_uint64 (max_fragment_id),
1325 GNUNET_MY_result_spec_uint64 (max_message_id),
1326 GNUNET_MY_result_spec_uint64 (max_group_generation),
1327 GNUNET_MY_result_spec_end
1328 };
1329
1330 ret = GNUNET_MY_extract_result (stmt, results_select);
1331
1332 if (GNUNET_OK != ret)
1333 {
1334 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1335 "mysql extract_result", stmt);
1336 return GNUNET_SYSERR;
1337 }
1338
1339 if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
1340 {
1341 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1342 "mysql_stmt_reset", stmt);
1343 return GNUNET_SYSERR;
1344 }
1345
1346 return ret;
1347}
1348
1349/**
1350 * Retrieve the max. values of state counters for a channel.
1351 *
1352 * @see GNUNET_PSYCSTORE_counters_get()
1353 *
1354 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1355 */
1356static int
1357counters_state_get (void *cls,
1358 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1359 uint64_t *max_state_message_id)
1360{
1361 struct Plugin *plugin = cls;
1362
1363 struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_counters_state;
1364
1365 int ret = GNUNET_SYSERR;
1366
1367 struct GNUNET_MY_QueryParam params_select[] = {
1368 GNUNET_MY_query_param_auto_from_type (channel_key),
1369 GNUNET_MY_query_param_end
1370 };
1371
1372 if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select))
1373 {
1374 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1375 "mysql execute prepared", stmt);
1376 return GNUNET_SYSERR;
1377 }
1378
1379 struct GNUNET_MY_ResultSpec results_select[] = {
1380 GNUNET_MY_result_spec_uint64 (max_state_message_id),
1381 GNUNET_MY_result_spec_end
1382 };
1383
1384 ret = GNUNET_MY_extract_result (stmt, results_select);
1385
1386 if (GNUNET_OK != ret)
1387 {
1388 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1389 "mysql extract_result", stmt);
1390 return GNUNET_SYSERR;
1391 }
1392
1393 if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
1394 {
1395 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1396 "mysql_stmt_reset", stmt);
1397 return GNUNET_SYSERR;
1398 }
1399
1400 return ret;
1401}
1402
1403
1404/**
1405 * Assign a value to a state variable.
1406 *
1407 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1408 */
1409static int
1410state_assign (struct Plugin *plugin, struct GNUNET_MYSQL_StatementHandle *stmt,
1411 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1412 const char *name, const void *value, size_t value_size)
1413{
1414 int ret = GNUNET_SYSERR;
1415
1416 struct GNUNET_MY_QueryParam params[] = {
1417 GNUNET_MY_query_param_auto_from_type (channel_key),
1418 GNUNET_MY_query_param_string (name),
1419 GNUNET_MY_query_param_fixed_size(value, value_size),
1420 GNUNET_MY_query_param_end
1421 };
1422
1423 ret = GNUNET_MY_exec_prepared (plugin->mc, stmt, params);
1424 if (GNUNET_OK != ret)
1425 {
1426 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1427 "mysql exec_prepared", stmt);
1428 return GNUNET_SYSERR;
1429 }
1430
1431 if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
1432 {
1433 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1434 "mysql_stmt_reset", stmt);
1435 return GNUNET_SYSERR;
1436 }
1437
1438 return ret;
1439}
1440
1441
1442static int
1443update_message_id (struct Plugin *plugin, struct GNUNET_MYSQL_StatementHandle *stmt,
1444 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1445 uint64_t message_id)
1446{
1447 struct GNUNET_MY_QueryParam params[] = {
1448 GNUNET_MY_query_param_uint64 (&message_id),
1449 GNUNET_MY_query_param_auto_from_type (channel_key),
1450 GNUNET_MY_query_param_end
1451 };
1452
1453 if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc,
1454 stmt,
1455 params))
1456 {
1457 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1458 "mysql execute prepared", stmt);
1459 return GNUNET_SYSERR;
1460 }
1461
1462 if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
1463 {
1464 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1465 "mysql_stmt_reset", stmt);
1466 return GNUNET_SYSERR;
1467 }
1468
1469 return GNUNET_OK;
1470}
1471
1472
1473/**
1474 * Begin modifying current state.
1475 */
1476static int
1477state_modify_begin (void *cls,
1478 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1479 uint64_t message_id, uint64_t state_delta)
1480{
1481 struct Plugin *plugin = cls;
1482
1483 if (state_delta > 0)
1484 {
1485 /**
1486 * We can only apply state modifiers in the current message if modifiers in
1487 * the previous stateful message (message_id - state_delta) were already
1488 * applied.
1489 */
1490
1491 uint64_t max_state_message_id = 0;
1492 int ret = counters_state_get (plugin, channel_key, &max_state_message_id);
1493 switch (ret)
1494 {
1495 case GNUNET_OK:
1496 case GNUNET_NO: // no state yet
1497 ret = GNUNET_OK;
1498 break;
1499 default:
1500 return ret;
1501 }
1502
1503 if (max_state_message_id < message_id - state_delta)
1504 return GNUNET_NO; /* some stateful messages not yet applied */
1505 else if (message_id - state_delta < max_state_message_id)
1506 return GNUNET_NO; /* changes already applied */
1507 }
1508
1509 if (TRANSACTION_NONE != plugin->transaction)
1510 {
1511 /** @todo FIXME: wait for other transaction to finish */
1512 return GNUNET_SYSERR;
1513 }
1514 return transaction_begin (plugin, TRANSACTION_STATE_MODIFY);
1515}
1516
1517
1518/**
1519 * Set the current value of state variable.
1520 *
1521 * @see GNUNET_PSYCSTORE_state_modify()
1522 *
1523 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1524 */
1525static int
1526state_modify_op (void *cls,
1527 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1528 enum GNUNET_PSYC_Operator op,
1529 const char *name, const void *value, size_t value_size)
1530{
1531 struct Plugin *plugin = cls;
1532 GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction);
1533
1534 switch (op)
1535 {
1536 case GNUNET_PSYC_OP_ASSIGN:
1537 return state_assign (plugin, plugin->insert_state_current,
1538 channel_key, name, value, value_size);
1539
1540 default: /** @todo implement more state operations */
1541 GNUNET_break (0);
1542 return GNUNET_SYSERR;
1543 }
1544}
1545
1546
1547/**
1548 * End modifying current state.
1549 */
1550static int
1551state_modify_end (void *cls,
1552 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1553 uint64_t message_id)
1554{
1555 struct Plugin *plugin = cls;
1556 GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction);
1557
1558 return
1559 GNUNET_OK == exec_channel (plugin, plugin->delete_state_empty, channel_key)
1560 && GNUNET_OK == update_message_id (plugin,
1561 plugin->update_max_state_message_id,
1562 channel_key, message_id)
1563 && GNUNET_OK == transaction_commit (plugin)
1564 ? GNUNET_OK : GNUNET_SYSERR;
1565}
1566
1567
1568/**
1569 * Begin state synchronization.
1570 */
1571static int
1572state_sync_begin (void *cls,
1573 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
1574{
1575 struct Plugin *plugin = cls;
1576 return exec_channel (plugin, plugin->delete_state_sync, channel_key);
1577}
1578
1579
1580/**
1581 * Assign current value of a state variable.
1582 *
1583 * @see GNUNET_PSYCSTORE_state_modify()
1584 *
1585 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1586 */
1587static int
1588state_sync_assign (void *cls,
1589 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1590 const char *name, const void *value, size_t value_size)
1591{
1592 struct Plugin *plugin = cls;
1593 return state_assign (cls, plugin->insert_state_sync,
1594 channel_key, name, value, value_size);
1595}
1596
1597
1598/**
1599 * End modifying current state.
1600 */
1601static int
1602state_sync_end (void *cls,
1603 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1604 uint64_t max_state_message_id,
1605 uint64_t state_hash_message_id)
1606{
1607 struct Plugin *plugin = cls;
1608 int ret = GNUNET_SYSERR;
1609
1610 if (TRANSACTION_NONE != plugin->transaction)
1611 {
1612 /** @todo FIXME: wait for other transaction to finish */
1613 return GNUNET_SYSERR;
1614 }
1615
1616 GNUNET_OK == transaction_begin (plugin, TRANSACTION_STATE_SYNC)
1617 && GNUNET_OK == exec_channel (plugin, plugin->delete_state, channel_key)
1618 && GNUNET_OK == exec_channel (plugin, plugin->insert_state_from_sync,
1619 channel_key)
1620 && GNUNET_OK == exec_channel (plugin, plugin->delete_state_sync,
1621 channel_key)
1622 && GNUNET_OK == update_message_id (plugin,
1623 plugin->update_state_hash_message_id,
1624 channel_key, state_hash_message_id)
1625 && GNUNET_OK == update_message_id (plugin,
1626 plugin->update_max_state_message_id,
1627 channel_key, max_state_message_id)
1628 && GNUNET_OK == transaction_commit (plugin)
1629 ? ret = GNUNET_OK
1630 : transaction_rollback (plugin);
1631 return ret;
1632}
1633
1634
1635/**
1636 * Delete the whole state.
1637 *
1638 * @see GNUNET_PSYCSTORE_state_reset()
1639 *
1640 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1641 */
1642static int
1643state_reset (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
1644{
1645 struct Plugin *plugin = cls;
1646 return exec_channel (plugin, plugin->delete_state, channel_key);
1647}
1648
1649
1650/**
1651 * Update signed values of state variables in the state store.
1652 *
1653 * @see GNUNET_PSYCSTORE_state_hash_update()
1654 *
1655 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1656 */
1657static int
1658state_update_signed (void *cls,
1659 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
1660{
1661 struct Plugin *plugin = cls;
1662 return exec_channel (plugin, plugin->update_state_signed, channel_key);
1663}
1664
1665
1666/**
1667 * Retrieve a state variable by name.
1668 *
1669 * @see GNUNET_PSYCSTORE_state_get()
1670 *
1671 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1672 */
1673static int
1674state_get (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1675 const char *name, GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls)
1676{
1677 struct Plugin *plugin = cls;
1678 int ret = GNUNET_SYSERR;
1679 int sql_ret ;
1680
1681 struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_state_one;
1682
1683 struct GNUNET_MY_QueryParam params_select[] = {
1684 GNUNET_MY_query_param_auto_from_type (channel_key),
1685 GNUNET_MY_query_param_string (name),
1686 GNUNET_MY_query_param_end
1687 };
1688
1689 void *value_current = NULL;
1690 size_t value_size = 0;
1691
1692 struct GNUNET_MY_ResultSpec results[] = {
1693 GNUNET_MY_result_spec_variable_size (&value_current, &value_size),
1694 GNUNET_MY_result_spec_end
1695 };
1696
1697 if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select))
1698 {
1699 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1700 "mysql exec_prepared", stmt);
1701 }
1702 else
1703 {
1704 sql_ret = GNUNET_MY_extract_result (stmt, results);
1705 switch (sql_ret)
1706 {
1707 case GNUNET_NO:
1708 ret = GNUNET_NO;
1709 break;
1710
1711 case GNUNET_YES:
1712 ret = cb (cb_cls, name, value_current, value_size);
1713 break;
1714
1715 default:
1716 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1717 "mysql extract_result", stmt);
1718 }
1719 }
1720
1721 if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
1722 {
1723 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1724 "mysql_stmt_reset", stmt);
1725 return GNUNET_SYSERR;
1726 }
1727
1728 return ret;
1729}
1730
1731
1732/**
1733 * Retrieve all state variables for a channel with the given prefix.
1734 *
1735 * @see GNUNET_PSYCSTORE_state_get_prefix()
1736 *
1737 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1738 */
1739static int
1740state_get_prefix (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1741 const char *name, GNUNET_PSYCSTORE_StateCallback cb,
1742 void *cb_cls)
1743{
1744 struct Plugin *plugin = cls;
1745 int ret = GNUNET_SYSERR;
1746
1747 struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_state_prefix;
1748
1749 uint32_t name_len = (uint32_t) strlen (name);
1750
1751 struct GNUNET_MY_QueryParam params_select[] = {
1752 GNUNET_MY_query_param_auto_from_type (channel_key),
1753 GNUNET_MY_query_param_string (name),
1754 GNUNET_MY_query_param_uint32 (&name_len),
1755 GNUNET_MY_query_param_string (name),
1756 GNUNET_MY_query_param_end
1757 };
1758
1759 char *name2 = "";
1760 void *value_current = NULL;
1761 size_t value_size = 0;
1762
1763 struct GNUNET_MY_ResultSpec results[] = {
1764 GNUNET_MY_result_spec_string (&name2),
1765 GNUNET_MY_result_spec_variable_size (&value_current, &value_size),
1766 GNUNET_MY_result_spec_end
1767 };;
1768
1769 int sql_ret;
1770
1771 if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select))
1772 {
1773 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1774 "mysql exec_prepared", stmt);
1775 return GNUNET_SYSERR;
1776 }
1777
1778 do
1779 {
1780 sql_ret = GNUNET_MY_extract_result (stmt, results);
1781 switch (sql_ret)
1782 {
1783 case GNUNET_NO:
1784 if (ret != GNUNET_YES)
1785 ret = GNUNET_NO;
1786 break;
1787
1788 case GNUNET_YES:
1789 ret = cb (cb_cls, (const char *) name2, value_current, value_size);
1790
1791 if (ret != GNUNET_YES)
1792 sql_ret = GNUNET_NO;
1793 break;
1794
1795 default:
1796 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1797 "mysql extract_result", stmt);
1798 }
1799 }
1800 while (sql_ret == GNUNET_YES);
1801
1802 if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
1803 {
1804 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1805 "mysql_stmt_reset", stmt);
1806 return GNUNET_SYSERR;
1807 }
1808
1809 return ret;
1810}
1811
1812
1813/**
1814 * Retrieve all signed state variables for a channel.
1815 *
1816 * @see GNUNET_PSYCSTORE_state_get_signed()
1817 *
1818 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1819 */
1820static int
1821state_get_signed (void *cls,
1822 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1823 GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls)
1824{
1825 struct Plugin *plugin = cls;
1826 int ret = GNUNET_SYSERR;
1827
1828 struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_state_signed;
1829
1830 struct GNUNET_MY_QueryParam params_select[] = {
1831 GNUNET_MY_query_param_auto_from_type (channel_key),
1832 GNUNET_MY_query_param_end
1833 };
1834
1835 int sql_ret;
1836
1837 char *name = "";
1838 void *value_signed = NULL;
1839 size_t value_size = 0;
1840
1841 struct GNUNET_MY_ResultSpec results[] = {
1842 GNUNET_MY_result_spec_string (&name),
1843 GNUNET_MY_result_spec_variable_size (&value_signed, &value_size),
1844 GNUNET_MY_result_spec_end
1845 };
1846
1847 if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select))
1848 {
1849 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1850 "mysql exec_prepared", stmt);
1851 return GNUNET_SYSERR;
1852 }
1853
1854 do
1855 {
1856 sql_ret = GNUNET_MY_extract_result (stmt, results);
1857 switch (sql_ret)
1858 {
1859 case GNUNET_NO:
1860 if (ret != GNUNET_YES)
1861 ret = GNUNET_NO;
1862 break;
1863
1864 case GNUNET_YES:
1865 ret = cb (cb_cls, (const char *) name, value_signed, value_size);
1866
1867 if (ret != GNUNET_YES)
1868 sql_ret = GNUNET_NO;
1869 break;
1870
1871 default:
1872 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1873 "mysql extract_result", stmt);
1874 }
1875 }
1876 while (sql_ret == GNUNET_YES);
1877
1878 if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
1879 {
1880 LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1881 "mysql_stmt_reset", stmt);
1882 return GNUNET_SYSERR;
1883 }
1884
1885 return ret;
1886}
1887
1888
1889/**
1890 * Entry point for the plugin.
1891 *
1892 * @param cls The struct GNUNET_CONFIGURATION_Handle.
1893 * @return NULL on error, otherwise the plugin context
1894 */
1895void *
1896libgnunet_plugin_psycstore_mysql_init (void *cls)
1897{
1898 static struct Plugin plugin;
1899 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
1900 struct GNUNET_PSYCSTORE_PluginFunctions *api;
1901
1902 if (NULL != plugin.cfg)
1903 return NULL; /* can only initialize once! */
1904 memset (&plugin, 0, sizeof (struct Plugin));
1905 plugin.cfg = cfg;
1906 if (GNUNET_OK != database_setup (&plugin))
1907 {
1908 database_shutdown (&plugin);
1909 return NULL;
1910 }
1911 api = GNUNET_new (struct GNUNET_PSYCSTORE_PluginFunctions);
1912 api->cls = &plugin;
1913 api->membership_store = &mysql_membership_store;
1914 api->membership_test = &membership_test;
1915 api->fragment_store = &fragment_store;
1916 api->message_add_flags = &message_add_flags;
1917 api->fragment_get = &fragment_get;
1918 api->fragment_get_latest = &fragment_get_latest;
1919 api->message_get = &message_get;
1920 api->message_get_latest = &message_get_latest;
1921 api->message_get_fragment = &message_get_fragment;
1922 api->counters_message_get = &counters_message_get;
1923 api->counters_state_get = &counters_state_get;
1924 api->state_modify_begin = &state_modify_begin;
1925 api->state_modify_op = &state_modify_op;
1926 api->state_modify_end = &state_modify_end;
1927 api->state_sync_begin = &state_sync_begin;
1928 api->state_sync_assign = &state_sync_assign;
1929 api->state_sync_end = &state_sync_end;
1930 api->state_reset = &state_reset;
1931 api->state_update_signed = &state_update_signed;
1932 api->state_get = &state_get;
1933 api->state_get_prefix = &state_get_prefix;
1934 api->state_get_signed = &state_get_signed;
1935
1936 LOG (GNUNET_ERROR_TYPE_INFO, _("Mysql database running\n"));
1937 return api;
1938}
1939
1940
1941/**
1942 * Exit point from the plugin.
1943 *
1944 * @param cls The plugin context (as returned by "init")
1945 * @return Always NULL
1946 */
1947void *
1948libgnunet_plugin_psycstore_mysql_done (void *cls)
1949{
1950 struct GNUNET_PSYCSTORE_PluginFunctions *api = cls;
1951 struct Plugin *plugin = api->cls;
1952
1953 database_shutdown (plugin);
1954 plugin->cfg = NULL;
1955 GNUNET_free (api);
1956 LOG (GNUNET_ERROR_TYPE_DEBUG, "Mysql plugin is finished\n");
1957 return NULL;
1958}
1959
1960/* 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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2016 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file psycstore/plugin_psycstore_postgres.c
23 * @brief PostgresQL-based psycstore backend
24 * @author Daniel Golle
25 * @author Gabor X Toth
26 * @author Christian Grothoff
27 * @author Christophe Genevey
28 * @author Jeffrey Burdges
29 */
30
31#include "platform.h"
32#include "gnunet_psycstore_plugin.h"
33#include "gnunet_psycstore_service.h"
34#include "gnunet_multicast_service.h"
35#include "gnunet_crypto_lib.h"
36#include "gnunet_psyc_util_lib.h"
37#include "psycstore.h"
38#include "gnunet_pq_lib.h"
39
40/**
41 * After how many ms "busy" should a DB operation fail for good? A
42 * low value makes sure that we are more responsive to requests
43 * (especially PUTs). A high value guarantees a higher success rate
44 * (SELECTs in iterate can take several seconds despite LIMIT=1).
45 *
46 * The default value of 1s should ensure that users do not experience
47 * huge latencies while at the same time allowing operations to
48 * succeed with reasonable probability.
49 */
50#define BUSY_TIMEOUT_MS 1000
51
52#define DEBUG_PSYCSTORE GNUNET_EXTRA_LOGGING
53
54#define LOG(kind,...) GNUNET_log_from (kind, "psycstore-postgres", __VA_ARGS__)
55
56enum Transactions {
57 TRANSACTION_NONE = 0,
58 TRANSACTION_STATE_MODIFY,
59 TRANSACTION_STATE_SYNC,
60};
61
62/**
63 * Context for all functions in this plugin.
64 */
65struct Plugin
66{
67
68 const struct GNUNET_CONFIGURATION_Handle *cfg;
69
70 /**
71 * Native Postgres database handle.
72 */
73 PGconn *dbh;
74
75 enum Transactions transaction;
76
77 void *cls;
78};
79
80
81/**
82 * Initialize the database connections and associated
83 * data structures (create tables and indices
84 * as needed as well).
85 *
86 * @param plugin the plugin context (state for this module)
87 * @return #GNUNET_OK on success
88 */
89static int
90database_setup (struct Plugin *plugin)
91{
92 struct GNUNET_PQ_ExecuteStatement es[] = {
93 GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS channels (\n"
94 " id SERIAL,\n"
95 " pub_key BYTEA NOT NULL CHECK (LENGTH(pub_key)=32),\n"
96 " max_state_message_id BIGINT,\n"
97 " state_hash_message_id BIGINT,\n"
98 " PRIMARY KEY(id)\n"
99 ")"
100 "WITH OIDS"),
101 GNUNET_PQ_make_execute ("CREATE UNIQUE INDEX IF NOT EXISTS channel_pub_key_idx \n"
102 " ON channels (pub_key)"),
103 GNUNET_PQ_make_execute ("CREATE OR REPLACE FUNCTION get_chan_id(BYTEA) RETURNS INTEGER AS \n"
104 " 'SELECT id FROM channels WHERE pub_key=$1;' LANGUAGE SQL STABLE \n"
105 "RETURNS NULL ON NULL INPUT"),
106 GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS slaves (\n"
107 " id SERIAL,\n"
108 " pub_key BYTEA NOT NULL CHECK (LENGTH(pub_key)=32),\n"
109 " PRIMARY KEY(id)\n"
110 ")"
111 "WITH OIDS"),
112 GNUNET_PQ_make_execute ("CREATE UNIQUE INDEX IF NOT EXISTS slaves_pub_key_idx \n"
113 " ON slaves (pub_key)"),
114 GNUNET_PQ_make_execute ("CREATE OR REPLACE FUNCTION get_slave_id(BYTEA) RETURNS INTEGER AS \n"
115 " 'SELECT id FROM slaves WHERE pub_key=$1;' LANGUAGE SQL STABLE \n"
116 "RETURNS NULL ON NULL INPUT"),
117 GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS membership (\n"
118 " channel_id BIGINT NOT NULL REFERENCES channels(id),\n"
119 " slave_id BIGINT NOT NULL REFERENCES slaves(id),\n"
120 " did_join INT NOT NULL,\n"
121 " announced_at BIGINT NOT NULL,\n"
122 " effective_since BIGINT NOT NULL,\n"
123 " group_generation BIGINT NOT NULL\n"
124 ")"
125 "WITH OIDS"),
126 GNUNET_PQ_make_execute ("CREATE INDEX IF NOT EXISTS idx_membership_channel_id_slave_id "
127 "ON membership (channel_id, slave_id)"),
128 /** @todo messages table: add method_name column */
129 GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS messages (\n"
130 " channel_id BIGINT NOT NULL REFERENCES channels(id),\n"
131 " hop_counter INT NOT NULL,\n"
132 " signature BYTEA CHECK (LENGTH(signature)=64),\n"
133 " purpose BYTEA CHECK (LENGTH(purpose)=8),\n"
134 " fragment_id BIGINT NOT NULL,\n"
135 " fragment_offset BIGINT NOT NULL,\n"
136 " message_id BIGINT NOT NULL,\n"
137 " group_generation BIGINT NOT NULL,\n"
138 " multicast_flags INT NOT NULL,\n"
139 " psycstore_flags INT NOT NULL,\n"
140 " data BYTEA,\n"
141 " PRIMARY KEY (channel_id, fragment_id),\n"
142 " UNIQUE (channel_id, message_id, fragment_offset)\n"
143 ")"
144 "WITH OIDS"),
145 GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS state (\n"
146 " channel_id BIGINT NOT NULL REFERENCES channels(id),\n"
147 " name TEXT NOT NULL,\n"
148 " value_current BYTEA,\n"
149 " value_signed BYTEA,\n"
150 " PRIMARY KEY (channel_id, name)\n"
151 ")"
152 "WITH OIDS"),
153 GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS state_sync (\n"
154 " channel_id BIGINT NOT NULL REFERENCES channels(id),\n"
155 " name TEXT NOT NULL,\n"
156 " value BYTEA,\n"
157 " PRIMARY KEY (channel_id, name)\n"
158 ")"
159 "WITH OIDS"),
160 GNUNET_PQ_EXECUTE_STATEMENT_END
161 };
162
163 /* Open database and precompile statements */
164 plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg,
165 "psycstore-postgres");
166 if (NULL == plugin->dbh)
167 return GNUNET_SYSERR;
168 if (GNUNET_OK !=
169 GNUNET_PQ_exec_statements (plugin->dbh,
170 es))
171 {
172 PQfinish (plugin->dbh);
173 plugin->dbh = NULL;
174 return GNUNET_SYSERR;
175 }
176
177 /* Prepare statements */
178 {
179 struct GNUNET_PQ_PreparedStatement ps[] = {
180 GNUNET_PQ_make_prepare ("transaction_begin",
181 "BEGIN", 0),
182 GNUNET_PQ_make_prepare ("transaction_commit",
183 "COMMIT", 0),
184 GNUNET_PQ_make_prepare ("transaction_rollback",
185 "ROLLBACK", 0),
186 GNUNET_PQ_make_prepare ("insert_channel_key",
187 "INSERT INTO channels (pub_key) VALUES ($1)"
188 " ON CONFLICT DO NOTHING", 1),
189 GNUNET_PQ_make_prepare ("insert_slave_key",
190 "INSERT INTO slaves (pub_key) VALUES ($1)"
191 " ON CONFLICT DO NOTHING", 1),
192 GNUNET_PQ_make_prepare ("insert_membership",
193 "INSERT INTO membership\n"
194 " (channel_id, slave_id, did_join, announced_at,\n"
195 " effective_since, group_generation)\n"
196 "VALUES (get_chan_id($1),\n"
197 " get_slave_id($2),\n"
198 " $3, $4, $5, $6)", 6),
199 GNUNET_PQ_make_prepare ("select_membership",
200 "SELECT did_join FROM membership\n"
201 "WHERE channel_id = get_chan_id($1)\n"
202 " AND slave_id = get_slave_id($2)\n"
203 " AND effective_since <= $3 AND did_join = 1\n"
204 "ORDER BY announced_at DESC LIMIT 1", 3),
205 GNUNET_PQ_make_prepare ("insert_fragment",
206 "INSERT INTO messages\n"
207 " (channel_id, hop_counter, signature, purpose,\n"
208 " fragment_id, fragment_offset, message_id,\n"
209 " group_generation, multicast_flags, psycstore_flags, data)\n"
210 "VALUES (get_chan_id($1),\n"
211 " $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)"
212 "ON CONFLICT DO NOTHING", 11),
213 GNUNET_PQ_make_prepare ("update_message_flags",
214 "UPDATE messages\n"
215 "SET psycstore_flags = psycstore_flags | $1\n"
216 "WHERE channel_id = get_chan_id($2) \n"
217 " AND message_id = $3 AND fragment_offset = 0", 3),
218 GNUNET_PQ_make_prepare ("select_fragments",
219 "SELECT hop_counter, signature, purpose, fragment_id,\n"
220 " fragment_offset, message_id, group_generation,\n"
221 " multicast_flags, psycstore_flags, data\n"
222 "FROM messages\n"
223 "WHERE channel_id = get_chan_id($1) \n"
224 " AND $2 <= fragment_id AND fragment_id <= $3", 3),
225 /** @todo select_messages: add method_prefix filter */
226 GNUNET_PQ_make_prepare ("select_messages",
227 "SELECT hop_counter, signature, purpose, fragment_id,\n"
228 " fragment_offset, message_id, group_generation,\n"
229 " multicast_flags, psycstore_flags, data\n"
230 "FROM messages\n"
231 "WHERE channel_id = get_chan_id($1) \n"
232 " AND $2 <= message_id AND message_id <= $3\n"
233 "LIMIT $4;", 4),
234 /** @todo select_latest_messages: add method_prefix filter */
235 GNUNET_PQ_make_prepare ("select_latest_fragments",
236 "SELECT rev.hop_counter AS hop_counter,\n"
237 " rev.signature AS signature,\n"
238 " rev.purpose AS purpose,\n"
239 " rev.fragment_id AS fragment_id,\n"
240 " rev.fragment_offset AS fragment_offset,\n"
241 " rev.message_id AS message_id,\n"
242 " rev.group_generation AS group_generation,\n"
243 " rev.multicast_flags AS multicast_flags,\n"
244 " rev.psycstore_flags AS psycstore_flags,\n"
245 " rev.data AS data\n"
246 " FROM\n"
247 " (SELECT hop_counter, signature, purpose, fragment_id,\n"
248 " fragment_offset, message_id, group_generation,\n"
249 " multicast_flags, psycstore_flags, data \n"
250 " FROM messages\n"
251 " WHERE channel_id = get_chan_id($1) \n"
252 " ORDER BY fragment_id DESC\n"
253 " LIMIT $2) AS rev\n"
254 " ORDER BY rev.fragment_id;", 2),
255 GNUNET_PQ_make_prepare ("select_latest_messages",
256 "SELECT hop_counter, signature, purpose, fragment_id,\n"
257 " fragment_offset, message_id, group_generation,\n"
258 " multicast_flags, psycstore_flags, data\n"
259 "FROM messages\n"
260 "WHERE channel_id = get_chan_id($1)\n"
261 " AND message_id IN\n"
262 " (SELECT message_id\n"
263 " FROM messages\n"
264 " WHERE channel_id = get_chan_id($2) \n"
265 " GROUP BY message_id\n"
266 " ORDER BY message_id\n"
267 " DESC LIMIT $3)\n"
268 "ORDER BY fragment_id", 3),
269 GNUNET_PQ_make_prepare ("select_message_fragment",
270 "SELECT hop_counter, signature, purpose, fragment_id,\n"
271 " fragment_offset, message_id, group_generation,\n"
272 " multicast_flags, psycstore_flags, data\n"
273 "FROM messages\n"
274 "WHERE channel_id = get_chan_id($1) \n"
275 " AND message_id = $2 AND fragment_offset = $3", 3),
276 GNUNET_PQ_make_prepare ("select_counters_message",
277 "SELECT fragment_id, message_id, group_generation\n"
278 "FROM messages\n"
279 "WHERE channel_id = get_chan_id($1)\n"
280 "ORDER BY fragment_id DESC LIMIT 1", 1),
281 GNUNET_PQ_make_prepare ("select_counters_state",
282 "SELECT max_state_message_id\n"
283 "FROM channels\n"
284 "WHERE pub_key = $1 AND max_state_message_id IS NOT NULL", 1),
285 GNUNET_PQ_make_prepare ("update_max_state_message_id",
286 "UPDATE channels\n"
287 "SET max_state_message_id = $1\n"
288 "WHERE pub_key = $2", 2),
289
290 GNUNET_PQ_make_prepare ("update_state_hash_message_id",
291 "UPDATE channels\n"
292 "SET state_hash_message_id = $1\n"
293 "WHERE pub_key = $2", 2),
294 GNUNET_PQ_make_prepare ("insert_state_current",
295 "INSERT INTO state\n"
296 " (channel_id, name, value_current, value_signed)\n"
297 "SELECT new.channel_id, new.name,\n"
298 " new.value_current, old.value_signed\n"
299 "FROM (SELECT get_chan_id($1) AS channel_id,\n"
300 " $2::TEXT AS name, $3::BYTEA AS value_current) AS new\n"
301 "LEFT JOIN (SELECT channel_id, name, value_signed\n"
302 " FROM state) AS old\n"
303 "ON new.channel_id = old.channel_id AND new.name = old.name\n"
304 "ON CONFLICT (channel_id, name)\n"
305 " DO UPDATE SET value_current = EXCLUDED.value_current,\n"
306 " value_signed = EXCLUDED.value_signed", 3),
307 GNUNET_PQ_make_prepare ("delete_state_empty",
308 "DELETE FROM state\n"
309 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = $1)\n"
310 " AND (value_current IS NULL OR length(value_current) = 0)\n"
311 " AND (value_signed IS NULL OR length(value_signed) = 0)", 1),
312 GNUNET_PQ_make_prepare ("update_state_signed",
313 "UPDATE state\n"
314 "SET value_signed = value_current\n"
315 "WHERE channel_id = get_chan_id($1) ", 1),
316 GNUNET_PQ_make_prepare ("delete_state",
317 "DELETE FROM state\n"
318 "WHERE channel_id = get_chan_id($1) ", 1),
319 GNUNET_PQ_make_prepare ("insert_state_sync",
320 "INSERT INTO state_sync (channel_id, name, value)\n"
321 "VALUES (get_chan_id($1), $2, $3)", 3),
322 GNUNET_PQ_make_prepare ("insert_state_from_sync",
323 "INSERT INTO state\n"
324 " (channel_id, name, value_current, value_signed)\n"
325 "SELECT channel_id, name, value, value\n"
326 "FROM state_sync\n"
327 "WHERE channel_id = get_chan_id($1)", 1),
328 GNUNET_PQ_make_prepare ("delete_state_sync",
329 "DELETE FROM state_sync\n"
330 "WHERE channel_id = get_chan_id($1)", 1),
331 GNUNET_PQ_make_prepare ("select_state_one",
332 "SELECT value_current\n"
333 "FROM state\n"
334 "WHERE channel_id = get_chan_id($1)\n"
335 " AND name = $2", 2),
336 GNUNET_PQ_make_prepare ("select_state_prefix",
337 "SELECT name, value_current\n"
338 "FROM state\n"
339 "WHERE channel_id = get_chan_id($1)\n"
340 " AND (name = $2 OR substr(name, 1, $3) = $4)", 4),
341 GNUNET_PQ_make_prepare ("select_state_signed",
342 "SELECT name, value_signed\n"
343 "FROM state\n"
344 "WHERE channel_id = get_chan_id($1)\n"
345 " AND value_signed IS NOT NULL", 1),
346 GNUNET_PQ_PREPARED_STATEMENT_END
347 };
348
349 if (GNUNET_OK !=
350 GNUNET_PQ_prepare_statements (plugin->dbh,
351 ps))
352 {
353 PQfinish (plugin->dbh);
354 plugin->dbh = NULL;
355 return GNUNET_SYSERR;
356 }
357 }
358
359 return GNUNET_OK;
360}
361
362
363/**
364 * Shutdown database connection and associate data
365 * structures.
366 * @param plugin the plugin context (state for this module)
367 */
368static void
369database_shutdown (struct Plugin *plugin)
370{
371 PQfinish (plugin->dbh);
372 plugin->dbh = NULL;
373}
374
375
376/**
377 * Execute a prepared statement with a @a channel_key argument.
378 *
379 * @param plugin Plugin handle.
380 * @param stmt Statement to execute.
381 * @param channel_key Public key of the channel.
382 *
383 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
384 */
385static int
386exec_channel (struct Plugin *plugin, const char *stmt,
387 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
388{
389 struct GNUNET_PQ_QueryParam params[] = {
390 GNUNET_PQ_query_param_auto_from_type (channel_key),
391 GNUNET_PQ_query_param_end
392 };
393
394 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
395 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, stmt, params))
396 return GNUNET_SYSERR;
397
398 return GNUNET_OK;
399}
400
401
402/**
403 * Begin a transaction.
404 */
405static int
406transaction_begin (struct Plugin *plugin, enum Transactions transaction)
407{
408 struct GNUNET_PQ_QueryParam params[] = {
409 GNUNET_PQ_query_param_end
410 };
411
412 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
413 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "transaction_begin", params))
414 return GNUNET_SYSERR;
415
416 plugin->transaction = transaction;
417 return GNUNET_OK;
418}
419
420
421/**
422 * Commit current transaction.
423 */
424static int
425transaction_commit (struct Plugin *plugin)
426{
427 struct GNUNET_PQ_QueryParam params[] = {
428 GNUNET_PQ_query_param_end
429 };
430
431 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
432 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "transaction_commit", params))
433 return GNUNET_SYSERR;
434
435 plugin->transaction = TRANSACTION_NONE;
436 return GNUNET_OK;
437}
438
439
440/**
441 * Roll back current transaction.
442 */
443static int
444transaction_rollback (struct Plugin *plugin)
445{
446 struct GNUNET_PQ_QueryParam params[] = {
447 GNUNET_PQ_query_param_end
448 };
449
450 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
451 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "transaction_rollback", params))
452 return GNUNET_SYSERR;
453
454 plugin->transaction = TRANSACTION_NONE;
455 return GNUNET_OK;
456}
457
458
459static int
460channel_key_store (struct Plugin *plugin,
461 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
462{
463 struct GNUNET_PQ_QueryParam params[] = {
464 GNUNET_PQ_query_param_auto_from_type (channel_key),
465 GNUNET_PQ_query_param_end
466 };
467
468 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
469 GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
470 "insert_channel_key",
471 params))
472 return GNUNET_SYSERR;
473
474 return GNUNET_OK;
475}
476
477
478static int
479slave_key_store (struct Plugin *plugin,
480 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key)
481{
482 struct GNUNET_PQ_QueryParam params[] = {
483 GNUNET_PQ_query_param_auto_from_type (slave_key),
484 GNUNET_PQ_query_param_end
485 };
486
487 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
488 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "insert_slave_key", params))
489 return GNUNET_SYSERR;
490
491 return GNUNET_OK;
492}
493
494
495/**
496 * Store join/leave events for a PSYC channel in order to be able to answer
497 * membership test queries later.
498 *
499 * @see GNUNET_PSYCSTORE_membership_store()
500 *
501 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
502 */
503static int
504postgres_membership_store (void *cls,
505 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
506 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
507 int did_join,
508 uint64_t announced_at,
509 uint64_t effective_since,
510 uint64_t group_generation)
511{
512 struct Plugin *plugin = cls;
513 uint32_t idid_join = (uint32_t) did_join;
514
515 GNUNET_assert (TRANSACTION_NONE == plugin->transaction);
516
517 if ( (announced_at > INT64_MAX) ||
518 (effective_since > INT64_MAX) ||
519 (group_generation > INT64_MAX) )
520 {
521 GNUNET_break (0);
522 return GNUNET_SYSERR;
523 }
524
525 if ( (GNUNET_OK !=
526 channel_key_store (plugin, channel_key)) ||
527 (GNUNET_OK !=
528 slave_key_store (plugin, slave_key)) )
529 return GNUNET_SYSERR;
530
531 struct GNUNET_PQ_QueryParam params[] = {
532 GNUNET_PQ_query_param_auto_from_type (channel_key),
533 GNUNET_PQ_query_param_auto_from_type (slave_key),
534 GNUNET_PQ_query_param_uint32 (&idid_join),
535 GNUNET_PQ_query_param_uint64 (&announced_at),
536 GNUNET_PQ_query_param_uint64 (&effective_since),
537 GNUNET_PQ_query_param_uint64 (&group_generation),
538 GNUNET_PQ_query_param_end
539 };
540
541 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
542 GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
543 "insert_membership",
544 params))
545 return GNUNET_SYSERR;
546
547 return GNUNET_OK;
548}
549
550/**
551 * Test if a member was admitted to the channel at the given message ID.
552 *
553 * @see GNUNET_PSYCSTORE_membership_test()
554 *
555 * @return #GNUNET_YES if the member was admitted, #GNUNET_NO if not,
556 * #GNUNET_SYSERR if there was en error.
557 */
558static int
559membership_test (void *cls,
560 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
561 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
562 uint64_t message_id)
563{
564 struct Plugin *plugin = cls;
565
566 uint32_t did_join = 0;
567
568 struct GNUNET_PQ_QueryParam params_select[] = {
569 GNUNET_PQ_query_param_auto_from_type (channel_key),
570 GNUNET_PQ_query_param_auto_from_type (slave_key),
571 GNUNET_PQ_query_param_uint64 (&message_id),
572 GNUNET_PQ_query_param_end
573 };
574
575 struct GNUNET_PQ_ResultSpec results_select[] = {
576 GNUNET_PQ_result_spec_uint32 ("did_join", &did_join),
577 GNUNET_PQ_result_spec_end
578 };
579
580 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
581 GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, "select_membership",
582 params_select, results_select))
583 return GNUNET_SYSERR;
584
585 return GNUNET_OK;
586}
587
588/**
589 * Store a message fragment sent to a channel.
590 *
591 * @see GNUNET_PSYCSTORE_fragment_store()
592 *
593 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
594 */
595static int
596fragment_store (void *cls,
597 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
598 const struct GNUNET_MULTICAST_MessageHeader *msg,
599 uint32_t psycstore_flags)
600{
601 struct Plugin *plugin = cls;
602
603 GNUNET_assert (TRANSACTION_NONE == plugin->transaction);
604
605 uint64_t fragment_id = GNUNET_ntohll (msg->fragment_id);
606
607 uint64_t fragment_offset = GNUNET_ntohll (msg->fragment_offset);
608 uint64_t message_id = GNUNET_ntohll (msg->message_id);
609 uint64_t group_generation = GNUNET_ntohll (msg->group_generation);
610
611 uint32_t hop_counter = ntohl(msg->hop_counter);
612 uint32_t flags = ntohl(msg->flags);
613
614 if (fragment_id > INT64_MAX || fragment_offset > INT64_MAX ||
615 message_id > INT64_MAX || group_generation > INT64_MAX)
616 {
617 LOG(GNUNET_ERROR_TYPE_ERROR,
618 "Tried to store fragment with a field > INT64_MAX: "
619 "%lu, %lu, %lu, %lu\n", fragment_id, fragment_offset,
620 message_id, group_generation);
621 GNUNET_break (0);
622 return GNUNET_SYSERR;
623 }
624
625 if (GNUNET_OK != channel_key_store (plugin, channel_key))
626 return GNUNET_SYSERR;
627
628 struct GNUNET_PQ_QueryParam params_insert[] = {
629 GNUNET_PQ_query_param_auto_from_type (channel_key),
630 GNUNET_PQ_query_param_uint32 (&hop_counter),
631 GNUNET_PQ_query_param_auto_from_type (&msg->signature),
632 GNUNET_PQ_query_param_auto_from_type (&msg->purpose),
633 GNUNET_PQ_query_param_uint64 (&fragment_id),
634 GNUNET_PQ_query_param_uint64 (&fragment_offset),
635 GNUNET_PQ_query_param_uint64 (&message_id),
636 GNUNET_PQ_query_param_uint64 (&group_generation),
637 GNUNET_PQ_query_param_uint32 (&flags),
638 GNUNET_PQ_query_param_uint32 (&psycstore_flags),
639 GNUNET_PQ_query_param_fixed_size (&msg[1], ntohs (msg->header.size) - sizeof (*msg)),
640 GNUNET_PQ_query_param_end
641 };
642
643 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
644 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "insert_fragment", params_insert))
645 return GNUNET_SYSERR;
646
647 return GNUNET_OK;
648}
649
650/**
651 * Set additional flags for a given message.
652 *
653 * They are OR'd with any existing flags set.
654 *
655 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
656 */
657static int
658message_add_flags (void *cls,
659 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
660 uint64_t message_id,
661 uint32_t psycstore_flags)
662{
663 struct Plugin *plugin = cls;
664
665 struct GNUNET_PQ_QueryParam params_update[] = {
666 GNUNET_PQ_query_param_uint32 (&psycstore_flags),
667 GNUNET_PQ_query_param_auto_from_type (channel_key),
668 GNUNET_PQ_query_param_uint64 (&message_id),
669 GNUNET_PQ_query_param_end
670 };
671
672 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
673 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "update_message_flags", params_update))
674 return GNUNET_SYSERR;
675
676 return GNUNET_OK;
677}
678
679
680/**
681 * Closure for #fragment_rows.
682 */
683struct FragmentRowsContext {
684 GNUNET_PSYCSTORE_FragmentCallback cb;
685 void *cb_cls;
686
687 uint64_t *returned_fragments;
688
689 /* I preserved this but I do not see the point since
690 * it cannot stop the loop early and gets overwritten ?? */
691 int ret;
692};
693
694
695/**
696 * Callback that retrieves the results of a SELECT statement
697 * reading form the messages table.
698 *
699 * Only passed to GNUNET_PQ_eval_prepared_multi_select and
700 * has type GNUNET_PQ_PostgresResultHandler.
701 *
702 * @param cls closure
703 * @param result the postgres result
704 * @param num_result the number of results in @a result
705 */
706void fragment_rows (void *cls,
707 PGresult *res,
708 unsigned int num_results)
709{
710 struct FragmentRowsContext *c = cls;
711
712 for (unsigned int i=0;i<num_results;i++)
713 {
714 uint32_t hop_counter;
715 void *signature = NULL;
716 void *purpose = NULL;
717 size_t signature_size;
718 size_t purpose_size;
719 uint64_t fragment_id;
720 uint64_t fragment_offset;
721 uint64_t message_id;
722 uint64_t group_generation;
723 uint32_t flags;
724 void *buf;
725 size_t buf_size;
726 uint32_t msg_flags;
727 struct GNUNET_PQ_ResultSpec results[] = {
728 GNUNET_PQ_result_spec_uint32 ("hop_counter", &hop_counter),
729 GNUNET_PQ_result_spec_variable_size ("signature", &signature, &signature_size),
730 GNUNET_PQ_result_spec_variable_size ("purpose", &purpose, &purpose_size),
731 GNUNET_PQ_result_spec_uint64 ("fragment_id", &fragment_id),
732 GNUNET_PQ_result_spec_uint64 ("fragment_offset", &fragment_offset),
733 GNUNET_PQ_result_spec_uint64 ("message_id", &message_id),
734 GNUNET_PQ_result_spec_uint64 ("group_generation", &group_generation),
735 GNUNET_PQ_result_spec_uint32 ("multicast_flags", &msg_flags),
736 GNUNET_PQ_result_spec_uint32 ("psycstore_flags", &flags),
737 GNUNET_PQ_result_spec_variable_size ("data", &buf, &buf_size),
738 GNUNET_PQ_result_spec_end
739 };
740 struct GNUNET_MULTICAST_MessageHeader *mp;
741
742 if (GNUNET_YES != GNUNET_PQ_extract_result (res, results, i))
743 {
744 GNUNET_PQ_cleanup_result(results); /* missing previously, a memory leak?? */
745 break; /* nothing more?? */
746 }
747
748 mp = GNUNET_malloc (sizeof (*mp) + buf_size);
749
750 mp->header.size = htons (sizeof (*mp) + buf_size);
751 mp->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE);
752 mp->hop_counter = htonl (hop_counter);
753 GNUNET_memcpy (&mp->signature,
754 signature, signature_size);
755 GNUNET_memcpy (&mp->purpose,
756 purpose, purpose_size);
757 mp->fragment_id = GNUNET_htonll (fragment_id);
758 mp->fragment_offset = GNUNET_htonll (fragment_offset);
759 mp->message_id = GNUNET_htonll (message_id);
760 mp->group_generation = GNUNET_htonll (group_generation);
761 mp->flags = htonl(msg_flags);
762
763 GNUNET_memcpy (&mp[1],
764 buf, buf_size);
765 GNUNET_PQ_cleanup_result(results);
766 c->ret = c->cb (c->cb_cls, mp, (enum GNUNET_PSYCSTORE_MessageFlags) flags);
767 if (NULL != c->returned_fragments)
768 (*c->returned_fragments)++;
769 }
770}
771
772
773static int
774fragment_select (struct Plugin *plugin,
775 const char *stmt,
776 struct GNUNET_PQ_QueryParam *params,
777 uint64_t *returned_fragments,
778 GNUNET_PSYCSTORE_FragmentCallback cb,
779 void *cb_cls)
780{
781 /* Stack based closure */
782 struct FragmentRowsContext frc = {
783 .cb = cb,
784 .cb_cls = cb_cls,
785 .returned_fragments = returned_fragments,
786 .ret = GNUNET_SYSERR
787 };
788
789 if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
790 stmt, params,
791 &fragment_rows, &frc))
792 return GNUNET_SYSERR;
793 return frc.ret; /* GNUNET_OK ?? */
794}
795
796/**
797 * Retrieve a message fragment range by fragment ID.
798 *
799 * @see GNUNET_PSYCSTORE_fragment_get()
800 *
801 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
802 */
803static int
804fragment_get (void *cls,
805 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
806 uint64_t first_fragment_id,
807 uint64_t last_fragment_id,
808 uint64_t *returned_fragments,
809 GNUNET_PSYCSTORE_FragmentCallback cb,
810 void *cb_cls)
811{
812 struct Plugin *plugin = cls;
813 struct GNUNET_PQ_QueryParam params_select[] = {
814 GNUNET_PQ_query_param_auto_from_type (channel_key),
815 GNUNET_PQ_query_param_uint64 (&first_fragment_id),
816 GNUNET_PQ_query_param_uint64 (&last_fragment_id),
817 GNUNET_PQ_query_param_end
818 };
819
820 *returned_fragments = 0;
821 return fragment_select (plugin,
822 "select_fragments",
823 params_select,
824 returned_fragments,
825 cb, cb_cls);
826}
827
828
829/**
830 * Retrieve a message fragment range by fragment ID.
831 *
832 * @see GNUNET_PSYCSTORE_fragment_get_latest()
833 *
834 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
835 */
836static int
837fragment_get_latest (void *cls,
838 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
839 uint64_t fragment_limit,
840 uint64_t *returned_fragments,
841 GNUNET_PSYCSTORE_FragmentCallback cb,
842 void *cb_cls)
843{
844 struct Plugin *plugin = cls;
845
846 *returned_fragments = 0;
847
848 struct GNUNET_PQ_QueryParam params_select[] = {
849 GNUNET_PQ_query_param_auto_from_type (channel_key),
850 GNUNET_PQ_query_param_uint64 (&fragment_limit),
851 GNUNET_PQ_query_param_end
852 };
853
854 return fragment_select (plugin,
855 "select_latest_fragments",
856 params_select,
857 returned_fragments,
858 cb, cb_cls);
859}
860
861
862/**
863 * Retrieve all fragments of a message ID range.
864 *
865 * @see GNUNET_PSYCSTORE_message_get()
866 *
867 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
868 */
869static int
870message_get (void *cls,
871 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
872 uint64_t first_message_id,
873 uint64_t last_message_id,
874 uint64_t fragment_limit,
875 uint64_t *returned_fragments,
876 GNUNET_PSYCSTORE_FragmentCallback cb,
877 void *cb_cls)
878{
879 struct Plugin *plugin = cls;
880 struct GNUNET_PQ_QueryParam params_select[] = {
881 GNUNET_PQ_query_param_auto_from_type (channel_key),
882 GNUNET_PQ_query_param_uint64 (&first_message_id),
883 GNUNET_PQ_query_param_uint64 (&last_message_id),
884 GNUNET_PQ_query_param_uint64 (&fragment_limit),
885 GNUNET_PQ_query_param_end
886 };
887
888 if (0 == fragment_limit)
889 fragment_limit = INT64_MAX;
890 *returned_fragments = 0;
891 return fragment_select (plugin,
892 "select_messages",
893 params_select,
894 returned_fragments,
895 cb, cb_cls);
896}
897
898
899/**
900 * Retrieve all fragments of the latest messages.
901 *
902 * @see GNUNET_PSYCSTORE_message_get_latest()
903 *
904 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
905 */
906static int
907message_get_latest (void *cls,
908 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
909 uint64_t message_limit,
910 uint64_t *returned_fragments,
911 GNUNET_PSYCSTORE_FragmentCallback cb,
912 void *cb_cls)
913{
914 struct Plugin *plugin = cls;
915 struct GNUNET_PQ_QueryParam params_select[] = {
916 GNUNET_PQ_query_param_auto_from_type (channel_key),
917 GNUNET_PQ_query_param_auto_from_type (channel_key),
918 GNUNET_PQ_query_param_uint64 (&message_limit),
919 GNUNET_PQ_query_param_end
920 };
921
922 *returned_fragments = 0;
923 return fragment_select (plugin,
924 "select_latest_messages",
925 params_select,
926 returned_fragments,
927 cb, cb_cls);
928}
929
930
931/**
932 * Retrieve a fragment of message specified by its message ID and fragment
933 * offset.
934 *
935 * @see GNUNET_PSYCSTORE_message_get_fragment()
936 *
937 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
938 */
939static int
940message_get_fragment (void *cls,
941 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
942 uint64_t message_id,
943 uint64_t fragment_offset,
944 GNUNET_PSYCSTORE_FragmentCallback cb,
945 void *cb_cls)
946{
947 struct Plugin *plugin = cls;
948 const char *stmt = "select_message_fragment";
949
950 struct GNUNET_PQ_QueryParam params_select[] = {
951 GNUNET_PQ_query_param_auto_from_type (channel_key),
952 GNUNET_PQ_query_param_uint64 (&message_id),
953 GNUNET_PQ_query_param_uint64 (&fragment_offset),
954 GNUNET_PQ_query_param_end
955 };
956
957 /* Stack based closure */
958 struct FragmentRowsContext frc = {
959 .cb = cb,
960 .cb_cls = cb_cls,
961 .returned_fragments = NULL,
962 .ret = GNUNET_SYSERR
963 };
964
965 if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
966 stmt, params_select,
967 &fragment_rows, &frc))
968 return GNUNET_SYSERR;
969 return frc.ret; /* GNUNET_OK ?? */
970}
971
972/**
973 * Retrieve the max. values of message counters for a channel.
974 *
975 * @see GNUNET_PSYCSTORE_counters_get()
976 *
977 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
978 */
979static int
980counters_message_get (void *cls,
981 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
982 uint64_t *max_fragment_id,
983 uint64_t *max_message_id,
984 uint64_t *max_group_generation)
985{
986 struct Plugin *plugin = cls;
987
988 const char *stmt = "select_counters_message";
989
990 struct GNUNET_PQ_QueryParam params_select[] = {
991 GNUNET_PQ_query_param_auto_from_type (channel_key),
992 GNUNET_PQ_query_param_end
993 };
994
995 struct GNUNET_PQ_ResultSpec results_select[] = {
996 GNUNET_PQ_result_spec_uint64 ("fragment_id", max_fragment_id),
997 GNUNET_PQ_result_spec_uint64 ("message_id", max_message_id),
998 GNUNET_PQ_result_spec_uint64 ("group_generation", max_group_generation),
999 GNUNET_PQ_result_spec_end
1000 };
1001
1002 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
1003 GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, stmt,
1004 params_select, results_select))
1005 return GNUNET_SYSERR;
1006
1007 return GNUNET_OK;
1008}
1009
1010/**
1011 * Retrieve the max. values of state counters for a channel.
1012 *
1013 * @see GNUNET_PSYCSTORE_counters_get()
1014 *
1015 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1016 */
1017static int
1018counters_state_get (void *cls,
1019 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1020 uint64_t *max_state_message_id)
1021{
1022 struct Plugin *plugin = cls;
1023
1024 const char *stmt = "select_counters_state";
1025
1026 struct GNUNET_PQ_QueryParam params_select[] = {
1027 GNUNET_PQ_query_param_auto_from_type (channel_key),
1028 GNUNET_PQ_query_param_end
1029 };
1030
1031 struct GNUNET_PQ_ResultSpec results_select[] = {
1032 GNUNET_PQ_result_spec_uint64 ("max_state_message_id", max_state_message_id),
1033 GNUNET_PQ_result_spec_end
1034 };
1035
1036 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
1037 GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, stmt,
1038 params_select, results_select))
1039 return GNUNET_SYSERR;
1040
1041 return GNUNET_OK;
1042}
1043
1044
1045/**
1046 * Assign a value to a state variable.
1047 *
1048 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1049 */
1050static int
1051state_assign (struct Plugin *plugin, const char *stmt,
1052 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1053 const char *name, const void *value, size_t value_size)
1054{
1055 struct GNUNET_PQ_QueryParam params[] = {
1056 GNUNET_PQ_query_param_auto_from_type (channel_key),
1057 GNUNET_PQ_query_param_string (name),
1058 GNUNET_PQ_query_param_fixed_size (value, value_size),
1059 GNUNET_PQ_query_param_end
1060 };
1061
1062 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
1063 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, stmt, params))
1064 return GNUNET_SYSERR;
1065
1066 return GNUNET_OK;
1067}
1068
1069
1070static int
1071update_message_id (struct Plugin *plugin,
1072 const char *stmt,
1073 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1074 uint64_t message_id)
1075{
1076 struct GNUNET_PQ_QueryParam params[] = {
1077 GNUNET_PQ_query_param_uint64 (&message_id),
1078 GNUNET_PQ_query_param_auto_from_type (channel_key),
1079 GNUNET_PQ_query_param_end
1080 };
1081
1082 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
1083 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, stmt, params))
1084 return GNUNET_SYSERR;
1085
1086 return GNUNET_OK;
1087}
1088
1089
1090/**
1091 * Begin modifying current state.
1092 */
1093static int
1094state_modify_begin (void *cls,
1095 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1096 uint64_t message_id, uint64_t state_delta)
1097{
1098 struct Plugin *plugin = cls;
1099
1100 if (state_delta > 0)
1101 {
1102 /**
1103 * We can only apply state modifiers in the current message if modifiers in
1104 * the previous stateful message (message_id - state_delta) were already
1105 * applied.
1106 */
1107
1108 uint64_t max_state_message_id = 0;
1109 int ret = counters_state_get (plugin, channel_key, &max_state_message_id);
1110 switch (ret)
1111 {
1112 case GNUNET_OK:
1113 case GNUNET_NO: // no state yet
1114 ret = GNUNET_OK;
1115 break;
1116
1117 default:
1118 return ret;
1119 }
1120
1121 if (max_state_message_id < message_id - state_delta)
1122 return GNUNET_NO; /* some stateful messages not yet applied */
1123 else if (message_id - state_delta < max_state_message_id)
1124 return GNUNET_NO; /* changes already applied */
1125 }
1126
1127 if (TRANSACTION_NONE != plugin->transaction)
1128 {
1129 /** @todo FIXME: wait for other transaction to finish */
1130 return GNUNET_SYSERR;
1131 }
1132 return transaction_begin (plugin, TRANSACTION_STATE_MODIFY);
1133}
1134
1135
1136/**
1137 * Set the current value of state variable.
1138 *
1139 * @see GNUNET_PSYCSTORE_state_modify()
1140 *
1141 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1142 */
1143static int
1144state_modify_op (void *cls,
1145 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1146 enum GNUNET_PSYC_Operator op,
1147 const char *name, const void *value, size_t value_size)
1148{
1149 struct Plugin *plugin = cls;
1150 GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction);
1151
1152 switch (op)
1153 {
1154 case GNUNET_PSYC_OP_ASSIGN:
1155 return state_assign (plugin, "insert_state_current",
1156 channel_key, name, value, value_size);
1157
1158 default: /** @todo implement more state operations */
1159 GNUNET_break (0);
1160 return GNUNET_SYSERR;
1161 }
1162}
1163
1164
1165/**
1166 * End modifying current state.
1167 */
1168static int
1169state_modify_end (void *cls,
1170 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1171 uint64_t message_id)
1172{
1173 struct Plugin *plugin = cls;
1174 GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction);
1175
1176 return
1177 GNUNET_OK == exec_channel (plugin, "delete_state_empty", channel_key)
1178 && GNUNET_OK == update_message_id (plugin,
1179 "update_max_state_message_id",
1180 channel_key, message_id)
1181 && GNUNET_OK == transaction_commit (plugin)
1182 ? GNUNET_OK : GNUNET_SYSERR;
1183}
1184
1185
1186/**
1187 * Begin state synchronization.
1188 */
1189static int
1190state_sync_begin (void *cls,
1191 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
1192{
1193 struct Plugin *plugin = cls;
1194 return exec_channel (plugin, "delete_state_sync", channel_key);
1195}
1196
1197
1198/**
1199 * Assign current value of a state variable.
1200 *
1201 * @see GNUNET_PSYCSTORE_state_modify()
1202 *
1203 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1204 */
1205static int
1206state_sync_assign (void *cls,
1207 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1208 const char *name, const void *value, size_t value_size)
1209{
1210 struct Plugin *plugin = cls;
1211 return state_assign (plugin, "insert_state_sync",
1212 channel_key, name, value, value_size);
1213}
1214
1215
1216/**
1217 * End modifying current state.
1218 */
1219static int
1220state_sync_end (void *cls,
1221 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1222 uint64_t max_state_message_id,
1223 uint64_t state_hash_message_id)
1224{
1225 struct Plugin *plugin = cls;
1226 int ret = GNUNET_SYSERR;
1227
1228 if (TRANSACTION_NONE != plugin->transaction)
1229 {
1230 /** @todo FIXME: wait for other transaction to finish */
1231 return GNUNET_SYSERR;
1232 }
1233
1234 GNUNET_OK == transaction_begin (plugin, TRANSACTION_STATE_SYNC)
1235 && GNUNET_OK == exec_channel (plugin, "delete_state", channel_key)
1236 && GNUNET_OK == exec_channel (plugin, "insert_state_from_sync",
1237 channel_key)
1238 && GNUNET_OK == exec_channel (plugin, "delete_state_sync",
1239 channel_key)
1240 && GNUNET_OK == update_message_id (plugin,
1241 "update_state_hash_message_id",
1242 channel_key, state_hash_message_id)
1243 && GNUNET_OK == update_message_id (plugin,
1244 "update_max_state_message_id",
1245 channel_key, max_state_message_id)
1246 && GNUNET_OK == transaction_commit (plugin)
1247 ? ret = GNUNET_OK
1248 : transaction_rollback (plugin);
1249 return ret;
1250}
1251
1252
1253/**
1254 * Delete the whole state.
1255 *
1256 * @see GNUNET_PSYCSTORE_state_reset()
1257 *
1258 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1259 */
1260static int
1261state_reset (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
1262{
1263 struct Plugin *plugin = cls;
1264 return exec_channel (plugin, "delete_state", channel_key);
1265}
1266
1267
1268/**
1269 * Update signed values of state variables in the state store.
1270 *
1271 * @see GNUNET_PSYCSTORE_state_hash_update()
1272 *
1273 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1274 */
1275static int
1276state_update_signed (void *cls,
1277 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
1278{
1279 struct Plugin *plugin = cls;
1280 return exec_channel (plugin, "update_state_signed", channel_key);
1281}
1282
1283
1284/**
1285 * Retrieve a state variable by name.
1286 *
1287 * @see GNUNET_PSYCSTORE_state_get()
1288 *
1289 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1290 */
1291static int
1292state_get (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1293 const char *name, GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls)
1294{
1295 struct Plugin *plugin = cls;
1296
1297 const char *stmt = "select_state_one";
1298
1299 struct GNUNET_PQ_QueryParam params_select[] = {
1300 GNUNET_PQ_query_param_auto_from_type (channel_key),
1301 GNUNET_PQ_query_param_string (name),
1302 GNUNET_PQ_query_param_end
1303 };
1304
1305 void *value_current = NULL;
1306 size_t value_size = 0;
1307
1308 struct GNUNET_PQ_ResultSpec results_select[] = {
1309 GNUNET_PQ_result_spec_variable_size ("value_current", &value_current, &value_size),
1310 GNUNET_PQ_result_spec_end
1311 };
1312
1313 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
1314 GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, stmt,
1315 params_select, results_select))
1316 return GNUNET_SYSERR;
1317
1318 return cb (cb_cls, name, value_current,
1319 value_size);
1320}
1321
1322
1323
1324/**
1325 * Closure for #get_state_cb.
1326 */
1327struct GetStateContext {
1328 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key;
1329 // const char *name,
1330 GNUNET_PSYCSTORE_StateCallback cb;
1331 void *cb_cls;
1332
1333 const char *value_id;
1334
1335 /* I preserved this but I do not see the point since
1336 * it cannot stop the loop early and gets overwritten ?? */
1337 int ret;
1338};
1339
1340
1341/**
1342 * Callback that retrieves the results of a SELECT statement
1343 * reading form the state table.
1344 *
1345 * Only passed to GNUNET_PQ_eval_prepared_multi_select and
1346 * has type GNUNET_PQ_PostgresResultHandler.
1347 *
1348 * @param cls closure
1349 * @param result the postgres result
1350 * @param num_result the number of results in @a result
1351 */
1352static void
1353get_state_cb (void *cls,
1354 PGresult *res,
1355 unsigned int num_results)
1356{
1357 struct GetStateContext *c = cls;
1358
1359 for (unsigned int i=0;i<num_results;i++)
1360 {
1361 char *name = "";
1362 void *value = NULL;
1363 size_t value_size = 0;
1364
1365 struct GNUNET_PQ_ResultSpec results[] = {
1366 GNUNET_PQ_result_spec_string ("name", &name),
1367 GNUNET_PQ_result_spec_variable_size (c->value_id, &value, &value_size),
1368 GNUNET_PQ_result_spec_end
1369 };
1370
1371 if (GNUNET_YES != GNUNET_PQ_extract_result (res, results, i))
1372 {
1373 GNUNET_PQ_cleanup_result(results); /* previously invoked via PQclear?? */
1374 break; /* nothing more?? */
1375 }
1376
1377 c->ret = c->cb (c->cb_cls, (const char *) name, value, value_size);
1378 GNUNET_PQ_cleanup_result(results);
1379 }
1380}
1381
1382/**
1383 * Retrieve all state variables for a channel with the given prefix.
1384 *
1385 * @see GNUNET_PSYCSTORE_state_get_prefix()
1386 *
1387 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1388 */
1389static int
1390state_get_prefix (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1391 const char *name, GNUNET_PSYCSTORE_StateCallback cb,
1392 void *cb_cls)
1393{
1394 struct Plugin *plugin = cls;
1395
1396 const char *stmt = "select_state_prefix";
1397
1398 uint32_t name_len = (uint32_t) strlen (name);
1399
1400 struct GNUNET_PQ_QueryParam params_select[] = {
1401 GNUNET_PQ_query_param_auto_from_type (channel_key),
1402 GNUNET_PQ_query_param_string (name),
1403 GNUNET_PQ_query_param_uint32 (&name_len),
1404 GNUNET_PQ_query_param_string (name),
1405 GNUNET_PQ_query_param_end
1406 };
1407
1408 struct GetStateContext gsc = {
1409 .cb = cb,
1410 .cb_cls = cb_cls,
1411 .value_id = "value_current",
1412 .ret = GNUNET_NO
1413 };
1414
1415 if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
1416 stmt, params_select,
1417 &get_state_cb, &gsc))
1418 return GNUNET_SYSERR;
1419 return gsc.ret; /* GNUNET_OK ?? */
1420}
1421
1422
1423/**
1424 * Retrieve all signed state variables for a channel.
1425 *
1426 * @see GNUNET_PSYCSTORE_state_get_signed()
1427 *
1428 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1429 */
1430static int
1431state_get_signed (void *cls,
1432 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1433 GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls)
1434{
1435 struct Plugin *plugin = cls;
1436
1437 const char *stmt = "select_state_signed";
1438
1439 struct GNUNET_PQ_QueryParam params_select[] = {
1440 GNUNET_PQ_query_param_auto_from_type (channel_key),
1441 GNUNET_PQ_query_param_end
1442 };
1443
1444 struct GetStateContext gsc = {
1445 .cb = cb,
1446 .cb_cls = cb_cls,
1447 .value_id = "value_signed",
1448 .ret = GNUNET_NO
1449 };
1450
1451 if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
1452 stmt, params_select,
1453 &get_state_cb, &gsc))
1454 return GNUNET_SYSERR;
1455 return gsc.ret; /* GNUNET_OK ?? */
1456}
1457
1458
1459/**
1460 * Entry point for the plugin.
1461 *
1462 * @param cls The struct GNUNET_CONFIGURATION_Handle.
1463 * @return NULL on error, otherwise the plugin context
1464 */
1465void *
1466libgnunet_plugin_psycstore_postgres_init (void *cls)
1467{
1468 static struct Plugin plugin;
1469 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
1470 struct GNUNET_PSYCSTORE_PluginFunctions *api;
1471
1472 if (NULL != plugin.cfg)
1473 return NULL; /* can only initialize once! */
1474 memset (&plugin, 0, sizeof (struct Plugin));
1475 plugin.cfg = cfg;
1476 if (GNUNET_OK != database_setup (&plugin))
1477 {
1478 database_shutdown (&plugin);
1479 return NULL;
1480 }
1481 api = GNUNET_new (struct GNUNET_PSYCSTORE_PluginFunctions);
1482 api->cls = &plugin;
1483 api->membership_store = &postgres_membership_store;
1484 api->membership_test = &membership_test;
1485 api->fragment_store = &fragment_store;
1486 api->message_add_flags = &message_add_flags;
1487 api->fragment_get = &fragment_get;
1488 api->fragment_get_latest = &fragment_get_latest;
1489 api->message_get = &message_get;
1490 api->message_get_latest = &message_get_latest;
1491 api->message_get_fragment = &message_get_fragment;
1492 api->counters_message_get = &counters_message_get;
1493 api->counters_state_get = &counters_state_get;
1494 api->state_modify_begin = &state_modify_begin;
1495 api->state_modify_op = &state_modify_op;
1496 api->state_modify_end = &state_modify_end;
1497 api->state_sync_begin = &state_sync_begin;
1498 api->state_sync_assign = &state_sync_assign;
1499 api->state_sync_end = &state_sync_end;
1500 api->state_reset = &state_reset;
1501 api->state_update_signed = &state_update_signed;
1502 api->state_get = &state_get;
1503 api->state_get_prefix = &state_get_prefix;
1504 api->state_get_signed = &state_get_signed;
1505
1506 LOG (GNUNET_ERROR_TYPE_INFO, _("Postgres database running\n"));
1507 return api;
1508}
1509
1510
1511/**
1512 * Exit point from the plugin.
1513 *
1514 * @param cls The plugin context (as returned by "init")
1515 * @return Always NULL
1516 */
1517void *
1518libgnunet_plugin_psycstore_postgres_done (void *cls)
1519{
1520 struct GNUNET_PSYCSTORE_PluginFunctions *api = cls;
1521 struct Plugin *plugin = api->cls;
1522
1523 database_shutdown (plugin);
1524 plugin->cfg = NULL;
1525 GNUNET_free (api);
1526 LOG (GNUNET_ERROR_TYPE_DEBUG, "Postgres plugin has finished\n");
1527 return NULL;
1528}
1529
1530/* 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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file psycstore/plugin_psycstore_sqlite.c
23 * @brief sqlite-based psycstore backend
24 * @author Gabor X Toth
25 * @author Christian Grothoff
26 */
27
28/*
29 * FIXME: SQLite3 only supports signed 64-bit integers natively,
30 * thus it can only store 63 bits of the uint64_t's.
31 */
32
33#include "platform.h"
34#include "gnunet_psycstore_plugin.h"
35#include "gnunet_psycstore_service.h"
36#include "gnunet_multicast_service.h"
37#include "gnunet_crypto_lib.h"
38#include "gnunet_psyc_util_lib.h"
39#include "psycstore.h"
40#include <sqlite3.h>
41
42/**
43 * After how many ms "busy" should a DB operation fail for good? A
44 * low value makes sure that we are more responsive to requests
45 * (especially PUTs). A high value guarantees a higher success rate
46 * (SELECTs in iterate can take several seconds despite LIMIT=1).
47 *
48 * The default value of 1s should ensure that users do not experience
49 * huge latencies while at the same time allowing operations to
50 * succeed with reasonable probability.
51 */
52#define BUSY_TIMEOUT_MS 1000
53
54#define DEBUG_PSYCSTORE GNUNET_EXTRA_LOGGING
55
56/**
57 * Log an error message at log-level 'level' that indicates
58 * a failure of the command 'cmd' on file 'filename'
59 * with the message given by strerror(errno).
60 */
61#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)
62
63#define LOG(kind,...) GNUNET_log_from (kind, "psycstore-sqlite", __VA_ARGS__)
64
65enum Transactions {
66 TRANSACTION_NONE = 0,
67 TRANSACTION_STATE_MODIFY,
68 TRANSACTION_STATE_SYNC,
69};
70
71/**
72 * Context for all functions in this plugin.
73 */
74struct Plugin
75{
76
77 const struct GNUNET_CONFIGURATION_Handle *cfg;
78
79 /**
80 * Database filename.
81 */
82 char *fn;
83
84 /**
85 * Native SQLite database handle.
86 */
87 sqlite3 *dbh;
88
89 /**
90 * Current transaction.
91 */
92 enum Transactions transaction;
93
94 sqlite3_stmt *transaction_begin;
95
96 sqlite3_stmt *transaction_commit;
97
98 sqlite3_stmt *transaction_rollback;
99
100 /**
101 * Precompiled SQL for channel_key_store()
102 */
103 sqlite3_stmt *insert_channel_key;
104
105 /**
106 * Precompiled SQL for slave_key_store()
107 */
108 sqlite3_stmt *insert_slave_key;
109
110
111 /**
112 * Precompiled SQL for membership_store()
113 */
114 sqlite3_stmt *insert_membership;
115
116 /**
117 * Precompiled SQL for membership_test()
118 */
119 sqlite3_stmt *select_membership;
120
121
122 /**
123 * Precompiled SQL for fragment_store()
124 */
125 sqlite3_stmt *insert_fragment;
126
127 /**
128 * Precompiled SQL for message_add_flags()
129 */
130 sqlite3_stmt *update_message_flags;
131
132 /**
133 * Precompiled SQL for fragment_get()
134 */
135 sqlite3_stmt *select_fragments;
136
137 /**
138 * Precompiled SQL for fragment_get()
139 */
140 sqlite3_stmt *select_latest_fragments;
141
142 /**
143 * Precompiled SQL for message_get()
144 */
145 sqlite3_stmt *select_messages;
146
147 /**
148 * Precompiled SQL for message_get()
149 */
150 sqlite3_stmt *select_latest_messages;
151
152 /**
153 * Precompiled SQL for message_get_fragment()
154 */
155 sqlite3_stmt *select_message_fragment;
156
157 /**
158 * Precompiled SQL for counters_get_message()
159 */
160 sqlite3_stmt *select_counters_message;
161
162 /**
163 * Precompiled SQL for counters_get_state()
164 */
165 sqlite3_stmt *select_counters_state;
166
167 /**
168 * Precompiled SQL for state_modify_end()
169 */
170 sqlite3_stmt *update_state_hash_message_id;
171
172 /**
173 * Precompiled SQL for state_sync_end()
174 */
175 sqlite3_stmt *update_max_state_message_id;
176
177 /**
178 * Precompiled SQL for state_modify_op()
179 */
180 sqlite3_stmt *insert_state_current;
181
182 /**
183 * Precompiled SQL for state_modify_end()
184 */
185 sqlite3_stmt *delete_state_empty;
186
187 /**
188 * Precompiled SQL for state_set_signed()
189 */
190 sqlite3_stmt *update_state_signed;
191
192 /**
193 * Precompiled SQL for state_sync()
194 */
195 sqlite3_stmt *insert_state_sync;
196
197 /**
198 * Precompiled SQL for state_sync()
199 */
200 sqlite3_stmt *delete_state;
201
202 /**
203 * Precompiled SQL for state_sync()
204 */
205 sqlite3_stmt *insert_state_from_sync;
206
207 /**
208 * Precompiled SQL for state_sync()
209 */
210 sqlite3_stmt *delete_state_sync;
211
212 /**
213 * Precompiled SQL for state_get_signed()
214 */
215 sqlite3_stmt *select_state_signed;
216
217 /**
218 * Precompiled SQL for state_get()
219 */
220 sqlite3_stmt *select_state_one;
221
222 /**
223 * Precompiled SQL for state_get_prefix()
224 */
225 sqlite3_stmt *select_state_prefix;
226
227};
228
229#if DEBUG_PSYCSTORE
230
231static void
232sql_trace (void *cls, const char *sql)
233{
234 LOG (GNUNET_ERROR_TYPE_DEBUG, "SQL query:\n%s\n", sql);
235}
236
237#endif
238
239/**
240 * @brief Prepare a SQL statement
241 *
242 * @param dbh handle to the database
243 * @param sql SQL statement, UTF-8 encoded
244 * @param stmt set to the prepared statement
245 * @return 0 on success
246 */
247static int
248sql_prepare (sqlite3 *dbh, const char *sql, sqlite3_stmt **stmt)
249{
250 char *tail;
251 int result;
252
253 result = sqlite3_prepare_v2 (dbh, sql, strlen (sql), stmt,
254 (const char **) &tail);
255 LOG (GNUNET_ERROR_TYPE_DEBUG,
256 "Prepared `%s' / %p: %d\n", sql, *stmt, result);
257 if (result != SQLITE_OK)
258 LOG (GNUNET_ERROR_TYPE_ERROR,
259 _("Error preparing SQL query: %s\n %s\n"),
260 sqlite3_errmsg (dbh), sql);
261 return result;
262}
263
264
265/**
266 * @brief Prepare a SQL statement
267 *
268 * @param dbh handle to the database
269 * @param sql SQL statement, UTF-8 encoded
270 * @return 0 on success
271 */
272static int
273sql_exec (sqlite3 *dbh, const char *sql)
274{
275 int result;
276
277 result = sqlite3_exec (dbh, sql, NULL, NULL, NULL);
278 LOG (GNUNET_ERROR_TYPE_DEBUG,
279 "Executed `%s' / %d\n", sql, result);
280 if (result != SQLITE_OK)
281 LOG (GNUNET_ERROR_TYPE_ERROR,
282 _("Error executing SQL query: %s\n %s\n"),
283 sqlite3_errmsg (dbh), sql);
284 return result;
285}
286
287
288/**
289 * Initialize the database connections and associated
290 * data structures (create tables and indices
291 * as needed as well).
292 *
293 * @param plugin the plugin context (state for this module)
294 * @return GNUNET_OK on success
295 */
296static int
297database_setup (struct Plugin *plugin)
298{
299 char *filename;
300
301 if (GNUNET_OK !=
302 GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, "psycstore-sqlite",
303 "FILENAME", &filename))
304 {
305 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
306 "psycstore-sqlite", "FILENAME");
307 return GNUNET_SYSERR;
308 }
309 if (GNUNET_OK != GNUNET_DISK_file_test (filename))
310 {
311 if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (filename))
312 {
313 GNUNET_break (0);
314 GNUNET_free (filename);
315 return GNUNET_SYSERR;
316 }
317 }
318 /* filename should be UTF-8-encoded. If it isn't, it's a bug */
319 plugin->fn = filename;
320
321 /* Open database and precompile statements */
322 if (SQLITE_OK != sqlite3_open (plugin->fn, &plugin->dbh))
323 {
324 LOG (GNUNET_ERROR_TYPE_ERROR,
325 _("Unable to initialize SQLite: %s.\n"),
326 sqlite3_errmsg (plugin->dbh));
327 return GNUNET_SYSERR;
328 }
329
330#if DEBUG_PSYCSTORE
331 sqlite3_trace (plugin->dbh, &sql_trace, NULL);
332#endif
333
334 sql_exec (plugin->dbh, "PRAGMA temp_store=MEMORY");
335 sql_exec (plugin->dbh, "PRAGMA synchronous=NORMAL");
336 sql_exec (plugin->dbh, "PRAGMA legacy_file_format=OFF");
337 sql_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL");
338 sql_exec (plugin->dbh, "PRAGMA encoding=\"UTF-8\"");
339#if ! DEBUG_PSYCSTORE
340 sql_exec (plugin->dbh, "PRAGMA locking_mode=EXCLUSIVE");
341#endif
342 sql_exec (plugin->dbh, "PRAGMA page_size=4096");
343
344 sqlite3_busy_timeout (plugin->dbh, BUSY_TIMEOUT_MS);
345
346 /* Create tables */
347
348 sql_exec (plugin->dbh,
349 "CREATE TABLE IF NOT EXISTS channels (\n"
350 " id INTEGER PRIMARY KEY,\n"
351 " pub_key BLOB(32) UNIQUE,\n"
352 " max_state_message_id INTEGER,\n" // last applied state message ID
353 " state_hash_message_id INTEGER\n" // last message ID with a state hash
354 ");");
355
356 sql_exec (plugin->dbh,
357 "CREATE TABLE IF NOT EXISTS slaves (\n"
358 " id INTEGER PRIMARY KEY,\n"
359 " pub_key BLOB(32) UNIQUE\n"
360 ");");
361
362 sql_exec (plugin->dbh,
363 "CREATE TABLE IF NOT EXISTS membership (\n"
364 " channel_id INTEGER NOT NULL REFERENCES channels(id),\n"
365 " slave_id INTEGER NOT NULL REFERENCES slaves(id),\n"
366 " did_join INTEGER NOT NULL,\n"
367 " announced_at INTEGER NOT NULL,\n"
368 " effective_since INTEGER NOT NULL,\n"
369 " group_generation INTEGER NOT NULL\n"
370 ");");
371 sql_exec (plugin->dbh,
372 "CREATE INDEX IF NOT EXISTS idx_membership_channel_id_slave_id "
373 "ON membership (channel_id, slave_id);");
374
375 /** @todo messages table: add method_name column */
376 sql_exec (plugin->dbh,
377 "CREATE TABLE IF NOT EXISTS messages (\n"
378 " channel_id INTEGER NOT NULL REFERENCES channels(id),\n"
379 " hop_counter INTEGER NOT NULL,\n"
380 " signature BLOB,\n"
381 " purpose BLOB,\n"
382 " fragment_id INTEGER NOT NULL,\n"
383 " fragment_offset INTEGER NOT NULL,\n"
384 " message_id INTEGER NOT NULL,\n"
385 " group_generation INTEGER NOT NULL,\n"
386 " multicast_flags INTEGER NOT NULL,\n"
387 " psycstore_flags INTEGER NOT NULL,\n"
388 " data BLOB,\n"
389 " PRIMARY KEY (channel_id, fragment_id),\n"
390 " UNIQUE (channel_id, message_id, fragment_offset)\n"
391 ");");
392
393 sql_exec (plugin->dbh,
394 "CREATE TABLE IF NOT EXISTS state (\n"
395 " channel_id INTEGER NOT NULL REFERENCES channels(id),\n"
396 " name TEXT NOT NULL,\n"
397 " value_current BLOB,\n"
398 " value_signed BLOB,\n"
399 " PRIMARY KEY (channel_id, name)\n"
400 ");");
401
402 sql_exec (plugin->dbh,
403 "CREATE TABLE IF NOT EXISTS state_sync (\n"
404 " channel_id INTEGER NOT NULL REFERENCES channels(id),\n"
405 " name TEXT NOT NULL,\n"
406 " value BLOB,\n"
407 " PRIMARY KEY (channel_id, name)\n"
408 ");");
409
410 /* Prepare statements */
411
412 sql_prepare (plugin->dbh, "BEGIN;", &plugin->transaction_begin);
413
414 sql_prepare (plugin->dbh, "COMMIT;", &plugin->transaction_commit);
415
416 sql_prepare (plugin->dbh, "ROLLBACK;", &plugin->transaction_rollback);
417
418 sql_prepare (plugin->dbh,
419 "INSERT OR IGNORE INTO channels (pub_key) VALUES (?);",
420 &plugin->insert_channel_key);
421
422 sql_prepare (plugin->dbh,
423 "INSERT OR IGNORE INTO slaves (pub_key) VALUES (?);",
424 &plugin->insert_slave_key);
425
426 sql_prepare (plugin->dbh,
427 "INSERT INTO membership\n"
428 " (channel_id, slave_id, did_join, announced_at,\n"
429 " effective_since, group_generation)\n"
430 "VALUES ((SELECT id FROM channels WHERE pub_key = ?),\n"
431 " (SELECT id FROM slaves WHERE pub_key = ?),\n"
432 " ?, ?, ?, ?);",
433 &plugin->insert_membership);
434
435 sql_prepare (plugin->dbh,
436 "SELECT did_join FROM membership\n"
437 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
438 " AND slave_id = (SELECT id FROM slaves WHERE pub_key = ?)\n"
439 " AND effective_since <= ? AND did_join = 1\n"
440 "ORDER BY announced_at DESC LIMIT 1;",
441 &plugin->select_membership);
442
443 sql_prepare (plugin->dbh,
444 "INSERT OR IGNORE INTO messages\n"
445 " (channel_id, hop_counter, signature, purpose,\n"
446 " fragment_id, fragment_offset, message_id,\n"
447 " group_generation, multicast_flags, psycstore_flags, data)\n"
448 "VALUES ((SELECT id FROM channels WHERE pub_key = ?),\n"
449 " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);",
450 &plugin->insert_fragment);
451
452 sql_prepare (plugin->dbh,
453 "UPDATE messages\n"
454 "SET psycstore_flags = psycstore_flags | ?\n"
455 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
456 " AND message_id = ? AND fragment_offset = 0;",
457 &plugin->update_message_flags);
458
459 sql_prepare (plugin->dbh,
460 "SELECT hop_counter, signature, purpose, fragment_id,\n"
461 " fragment_offset, message_id, group_generation,\n"
462 " multicast_flags, psycstore_flags, data\n"
463 "FROM messages\n"
464 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
465 " AND ? <= fragment_id AND fragment_id <= ?;",
466 &plugin->select_fragments);
467
468 /** @todo select_messages: add method_prefix filter */
469 sql_prepare (plugin->dbh,
470 "SELECT hop_counter, signature, purpose, fragment_id,\n"
471 " fragment_offset, message_id, group_generation,\n"
472 " multicast_flags, psycstore_flags, data\n"
473 "FROM messages\n"
474 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
475 " AND ? <= message_id AND message_id <= ?"
476 "LIMIT ?;",
477 &plugin->select_messages);
478
479 sql_prepare (plugin->dbh,
480 "SELECT * FROM\n"
481 "(SELECT hop_counter, signature, purpose, fragment_id,\n"
482 " fragment_offset, message_id, group_generation,\n"
483 " multicast_flags, psycstore_flags, data\n"
484 " FROM messages\n"
485 " WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
486 " ORDER BY fragment_id DESC\n"
487 " LIMIT ?)\n"
488 "ORDER BY fragment_id;",
489 &plugin->select_latest_fragments);
490
491 /** @todo select_latest_messages: add method_prefix filter */
492 sql_prepare (plugin->dbh,
493 "SELECT hop_counter, signature, purpose, fragment_id,\n"
494 " fragment_offset, message_id, group_generation,\n"
495 " multicast_flags, psycstore_flags, data\n"
496 "FROM messages\n"
497 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
498 " AND message_id IN\n"
499 " (SELECT message_id\n"
500 " FROM messages\n"
501 " WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
502 " GROUP BY message_id\n"
503 " ORDER BY message_id\n"
504 " DESC LIMIT ?)\n"
505 "ORDER BY fragment_id;",
506 &plugin->select_latest_messages);
507
508 sql_prepare (plugin->dbh,
509 "SELECT hop_counter, signature, purpose, fragment_id,\n"
510 " fragment_offset, message_id, group_generation,\n"
511 " multicast_flags, psycstore_flags, data\n"
512 "FROM messages\n"
513 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
514 " AND message_id = ? AND fragment_offset = ?;",
515 &plugin->select_message_fragment);
516
517 sql_prepare (plugin->dbh,
518 "SELECT fragment_id, message_id, group_generation\n"
519 "FROM messages\n"
520 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
521 "ORDER BY fragment_id DESC LIMIT 1;",
522 &plugin->select_counters_message);
523
524 sql_prepare (plugin->dbh,
525 "SELECT max_state_message_id\n"
526 "FROM channels\n"
527 "WHERE pub_key = ? AND max_state_message_id IS NOT NULL;",
528 &plugin->select_counters_state);
529
530 sql_prepare (plugin->dbh,
531 "UPDATE channels\n"
532 "SET max_state_message_id = ?\n"
533 "WHERE pub_key = ?;",
534 &plugin->update_max_state_message_id);
535
536 sql_prepare (plugin->dbh,
537 "UPDATE channels\n"
538 "SET state_hash_message_id = ?\n"
539 "WHERE pub_key = ?;",
540 &plugin->update_state_hash_message_id);
541
542 sql_prepare (plugin->dbh,
543 "INSERT OR REPLACE INTO state\n"
544 " (channel_id, name, value_current, value_signed)\n"
545 "SELECT new.channel_id, new.name,\n"
546 " new.value_current, old.value_signed\n"
547 "FROM (SELECT (SELECT id FROM channels WHERE pub_key = ?)\n"
548 " AS channel_id,\n"
549 " ? AS name, ? AS value_current) AS new\n"
550 "LEFT JOIN (SELECT channel_id, name, value_signed\n"
551 " FROM state) AS old\n"
552 "ON new.channel_id = old.channel_id AND new.name = old.name;",
553 &plugin->insert_state_current);
554
555 sql_prepare (plugin->dbh,
556 "DELETE FROM state\n"
557 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
558 " AND (value_current IS NULL OR length(value_current) = 0)\n"
559 " AND (value_signed IS NULL OR length(value_signed) = 0);",
560 &plugin->delete_state_empty);
561
562 sql_prepare (plugin->dbh,
563 "UPDATE state\n"
564 "SET value_signed = value_current\n"
565 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);",
566 &plugin->update_state_signed);
567
568 sql_prepare (plugin->dbh,
569 "DELETE FROM state\n"
570 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);",
571 &plugin->delete_state);
572
573 sql_prepare (plugin->dbh,
574 "INSERT INTO state_sync (channel_id, name, value)\n"
575 "VALUES ((SELECT id FROM channels WHERE pub_key = ?), ?, ?);",
576 &plugin->insert_state_sync);
577
578 sql_prepare (plugin->dbh,
579 "INSERT INTO state\n"
580 " (channel_id, name, value_current, value_signed)\n"
581 "SELECT channel_id, name, value, value\n"
582 "FROM state_sync\n"
583 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);",
584 &plugin->insert_state_from_sync);
585
586 sql_prepare (plugin->dbh,
587 "DELETE FROM state_sync\n"
588 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);",
589 &plugin->delete_state_sync);
590
591 sql_prepare (plugin->dbh,
592 "SELECT value_current\n"
593 "FROM state\n"
594 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
595 " AND name = ?;",
596 &plugin->select_state_one);
597
598 sql_prepare (plugin->dbh,
599 "SELECT name, value_current\n"
600 "FROM state\n"
601 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
602 " AND (name = ? OR substr(name, 1, ?) = ?);",
603 &plugin->select_state_prefix);
604
605 sql_prepare (plugin->dbh,
606 "SELECT name, value_signed\n"
607 "FROM state\n"
608 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)"
609 " AND value_signed IS NOT NULL;",
610 &plugin->select_state_signed);
611
612 return GNUNET_OK;
613}
614
615
616/**
617 * Shutdown database connection and associate data
618 * structures.
619 * @param plugin the plugin context (state for this module)
620 */
621static void
622database_shutdown (struct Plugin *plugin)
623{
624 int result;
625 sqlite3_stmt *stmt;
626 while (NULL != (stmt = sqlite3_next_stmt (plugin->dbh, NULL)))
627 {
628 result = sqlite3_finalize (stmt);
629 if (SQLITE_OK != result)
630 LOG (GNUNET_ERROR_TYPE_WARNING,
631 "Failed to close statement %p: %d\n", stmt, result);
632 }
633 if (SQLITE_OK != sqlite3_close (plugin->dbh))
634 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close");
635
636 GNUNET_free_non_null (plugin->fn);
637}
638
639/**
640 * Execute a prepared statement with a @a channel_key argument.
641 *
642 * @param plugin Plugin handle.
643 * @param stmt Statement to execute.
644 * @param channel_key Public key of the channel.
645 *
646 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
647 */
648static int
649exec_channel (struct Plugin *plugin, sqlite3_stmt *stmt,
650 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
651{
652 if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key,
653 sizeof (*channel_key), SQLITE_STATIC))
654 {
655 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
656 "sqlite3_bind");
657 }
658 else if (SQLITE_DONE != sqlite3_step (stmt))
659 {
660 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
661 "sqlite3_step");
662 }
663
664 if (SQLITE_OK != sqlite3_reset (stmt))
665 {
666 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
667 "sqlite3_reset");
668 return GNUNET_SYSERR;
669 }
670
671 return GNUNET_OK;
672}
673
674/**
675 * Begin a transaction.
676 */
677static int
678transaction_begin (struct Plugin *plugin, enum Transactions transaction)
679{
680 sqlite3_stmt *stmt = plugin->transaction_begin;
681
682 if (SQLITE_DONE != sqlite3_step (stmt))
683 {
684 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
685 "sqlite3_step");
686 }
687 if (SQLITE_OK != sqlite3_reset (stmt))
688 {
689 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
690 "sqlite3_reset");
691 return GNUNET_SYSERR;
692 }
693
694 plugin->transaction = transaction;
695 return GNUNET_OK;
696}
697
698
699/**
700 * Commit current transaction.
701 */
702static int
703transaction_commit (struct Plugin *plugin)
704{
705 sqlite3_stmt *stmt = plugin->transaction_commit;
706
707 if (SQLITE_DONE != sqlite3_step (stmt))
708 {
709 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
710 "sqlite3_step");
711 }
712 if (SQLITE_OK != sqlite3_reset (stmt))
713 {
714 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
715 "sqlite3_reset");
716 return GNUNET_SYSERR;
717 }
718
719 plugin->transaction = TRANSACTION_NONE;
720 return GNUNET_OK;
721}
722
723
724/**
725 * Roll back current transaction.
726 */
727static int
728transaction_rollback (struct Plugin *plugin)
729{
730 sqlite3_stmt *stmt = plugin->transaction_rollback;
731
732 if (SQLITE_DONE != sqlite3_step (stmt))
733 {
734 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
735 "sqlite3_step");
736 }
737 if (SQLITE_OK != sqlite3_reset (stmt))
738 {
739 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
740 "sqlite3_reset");
741 return GNUNET_SYSERR;
742 }
743 plugin->transaction = TRANSACTION_NONE;
744 return GNUNET_OK;
745}
746
747
748static int
749channel_key_store (struct Plugin *plugin,
750 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
751{
752 sqlite3_stmt *stmt = plugin->insert_channel_key;
753
754 if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key,
755 sizeof (*channel_key), SQLITE_STATIC))
756 {
757 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
758 "sqlite3_bind");
759 }
760 else if (SQLITE_DONE != sqlite3_step (stmt))
761 {
762 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
763 "sqlite3_step");
764 }
765
766 if (SQLITE_OK != sqlite3_reset (stmt))
767 {
768 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
769 "sqlite3_reset");
770 return GNUNET_SYSERR;
771 }
772
773 return GNUNET_OK;
774}
775
776
777static int
778slave_key_store (struct Plugin *plugin,
779 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key)
780{
781 sqlite3_stmt *stmt = plugin->insert_slave_key;
782
783 if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, slave_key,
784 sizeof (*slave_key), SQLITE_STATIC))
785 {
786 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
787 "sqlite3_bind");
788 }
789 else if (SQLITE_DONE != sqlite3_step (stmt))
790 {
791 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
792 "sqlite3_step");
793 }
794
795
796 if (SQLITE_OK != sqlite3_reset (stmt))
797 {
798 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
799 "sqlite3_reset");
800 return GNUNET_SYSERR;
801 }
802
803 return GNUNET_OK;
804}
805
806
807/**
808 * Store join/leave events for a PSYC channel in order to be able to answer
809 * membership test queries later.
810 *
811 * @see GNUNET_PSYCSTORE_membership_store()
812 *
813 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
814 */
815static int
816sqlite_membership_store (void *cls,
817 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
818 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
819 int did_join,
820 uint64_t announced_at,
821 uint64_t effective_since,
822 uint64_t group_generation)
823{
824 struct Plugin *plugin = cls;
825 sqlite3_stmt *stmt = plugin->insert_membership;
826
827 GNUNET_assert (TRANSACTION_NONE == plugin->transaction);
828
829 if (announced_at > INT64_MAX ||
830 effective_since > INT64_MAX ||
831 group_generation > INT64_MAX)
832 {
833 GNUNET_break (0);
834 return GNUNET_SYSERR;
835 }
836
837 if (GNUNET_OK != channel_key_store (plugin, channel_key)
838 || GNUNET_OK != slave_key_store (plugin, slave_key))
839 return GNUNET_SYSERR;
840
841 if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key,
842 sizeof (*channel_key), SQLITE_STATIC)
843 || SQLITE_OK != sqlite3_bind_blob (stmt, 2, slave_key,
844 sizeof (*slave_key), SQLITE_STATIC)
845 || SQLITE_OK != sqlite3_bind_int (stmt, 3, did_join)
846 || SQLITE_OK != sqlite3_bind_int64 (stmt, 4, announced_at)
847 || SQLITE_OK != sqlite3_bind_int64 (stmt, 5, effective_since)
848 || SQLITE_OK != sqlite3_bind_int64 (stmt, 6, group_generation))
849 {
850 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
851 "sqlite3_bind");
852 }
853 else if (SQLITE_DONE != sqlite3_step (stmt))
854 {
855 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
856 "sqlite3_step");
857 }
858
859 if (SQLITE_OK != sqlite3_reset (stmt))
860 {
861 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
862 "sqlite3_reset");
863 return GNUNET_SYSERR;
864 }
865
866 return GNUNET_OK;
867}
868
869/**
870 * Test if a member was admitted to the channel at the given message ID.
871 *
872 * @see GNUNET_PSYCSTORE_membership_test()
873 *
874 * @return #GNUNET_YES if the member was admitted, #GNUNET_NO if not,
875 * #GNUNET_SYSERR if there was en error.
876 */
877static int
878membership_test (void *cls,
879 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
880 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
881 uint64_t message_id)
882{
883 struct Plugin *plugin = cls;
884 sqlite3_stmt *stmt = plugin->select_membership;
885 int ret = GNUNET_SYSERR;
886
887 if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key,
888 sizeof (*channel_key), SQLITE_STATIC)
889 || SQLITE_OK != sqlite3_bind_blob (stmt, 2, slave_key,
890 sizeof (*slave_key), SQLITE_STATIC)
891 || SQLITE_OK != sqlite3_bind_int64 (stmt, 3, message_id))
892 {
893 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
894 "sqlite3_bind");
895 }
896 else
897 {
898 switch (sqlite3_step (stmt))
899 {
900 case SQLITE_DONE:
901 ret = GNUNET_NO;
902 break;
903 case SQLITE_ROW:
904 ret = GNUNET_YES;
905 }
906 }
907
908 if (SQLITE_OK != sqlite3_reset (stmt))
909 {
910 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
911 "sqlite3_reset");
912 }
913
914 return ret;
915}
916
917/**
918 * Store a message fragment sent to a channel.
919 *
920 * @see GNUNET_PSYCSTORE_fragment_store()
921 *
922 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
923 */
924static int
925fragment_store (void *cls,
926 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
927 const struct GNUNET_MULTICAST_MessageHeader *msg,
928 uint32_t psycstore_flags)
929{
930 struct Plugin *plugin = cls;
931 sqlite3_stmt *stmt = plugin->insert_fragment;
932
933 GNUNET_assert (TRANSACTION_NONE == plugin->transaction);
934
935 uint64_t fragment_id = GNUNET_ntohll (msg->fragment_id);
936 uint64_t fragment_offset = GNUNET_ntohll (msg->fragment_offset);
937 uint64_t message_id = GNUNET_ntohll (msg->message_id);
938 uint64_t group_generation = GNUNET_ntohll (msg->group_generation);
939
940 if (fragment_id > INT64_MAX || fragment_offset > INT64_MAX ||
941 message_id > INT64_MAX || group_generation > INT64_MAX)
942 {
943 LOG (GNUNET_ERROR_TYPE_ERROR,
944 "Tried to store fragment with a field > INT64_MAX: "
945 "%lu, %lu, %lu, %lu\n", fragment_id, fragment_offset,
946 message_id, group_generation);
947 GNUNET_break (0);
948 return GNUNET_SYSERR;
949 }
950
951 if (GNUNET_OK != channel_key_store (plugin, channel_key))
952 return GNUNET_SYSERR;
953
954 if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key,
955 sizeof (*channel_key), SQLITE_STATIC)
956 || SQLITE_OK != sqlite3_bind_int64 (stmt, 2, ntohl (msg->hop_counter) )
957 || SQLITE_OK != sqlite3_bind_blob (stmt, 3, (const void *) &msg->signature,
958 sizeof (msg->signature), SQLITE_STATIC)
959 || SQLITE_OK != sqlite3_bind_blob (stmt, 4, (const void *) &msg->purpose,
960 sizeof (msg->purpose), SQLITE_STATIC)
961 || SQLITE_OK != sqlite3_bind_int64 (stmt, 5, fragment_id)
962 || SQLITE_OK != sqlite3_bind_int64 (stmt, 6, fragment_offset)
963 || SQLITE_OK != sqlite3_bind_int64 (stmt, 7, message_id)
964 || SQLITE_OK != sqlite3_bind_int64 (stmt, 8, group_generation)
965 || SQLITE_OK != sqlite3_bind_int64 (stmt, 9, ntohl (msg->flags))
966 || SQLITE_OK != sqlite3_bind_int64 (stmt, 10, psycstore_flags)
967 || SQLITE_OK != sqlite3_bind_blob (stmt, 11, (const void *) &msg[1],
968 ntohs (msg->header.size)
969 - sizeof (*msg), SQLITE_STATIC))
970 {
971 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
972 "sqlite3_bind");
973 }
974 else if (SQLITE_DONE != sqlite3_step (stmt))
975 {
976 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
977 "sqlite3_step");
978 }
979
980 if (SQLITE_OK != sqlite3_reset (stmt))
981 {
982 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
983 "sqlite3_reset");
984 return GNUNET_SYSERR;
985 }
986
987 return GNUNET_OK;
988}
989
990/**
991 * Set additional flags for a given message.
992 *
993 * They are OR'd with any existing flags set.
994 *
995 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
996 */
997static int
998message_add_flags (void *cls,
999 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1000 uint64_t message_id,
1001 uint32_t psycstore_flags)
1002{
1003 struct Plugin *plugin = cls;
1004 sqlite3_stmt *stmt = plugin->update_message_flags;
1005 int ret = GNUNET_SYSERR;
1006
1007 if (SQLITE_OK != sqlite3_bind_int64 (stmt, 1, psycstore_flags)
1008 || SQLITE_OK != sqlite3_bind_blob (stmt, 2, channel_key,
1009 sizeof (*channel_key), SQLITE_STATIC)
1010 || SQLITE_OK != sqlite3_bind_int64 (stmt, 3, message_id))
1011 {
1012 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1013 "sqlite3_bind");
1014 }
1015 else
1016 {
1017 switch (sqlite3_step (stmt))
1018 {
1019 case SQLITE_DONE:
1020 ret = sqlite3_total_changes (plugin->dbh) > 0 ? GNUNET_OK : GNUNET_NO;
1021 break;
1022 default:
1023 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1024 "sqlite3_step");
1025 }
1026 }
1027
1028 if (SQLITE_OK != sqlite3_reset (stmt))
1029 {
1030 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1031 "sqlite3_reset");
1032 return GNUNET_SYSERR;
1033 }
1034
1035 return ret;
1036}
1037
1038static int
1039fragment_row (sqlite3_stmt *stmt, GNUNET_PSYCSTORE_FragmentCallback cb,
1040 void *cb_cls)
1041{
1042 int data_size = sqlite3_column_bytes (stmt, 9);
1043 struct GNUNET_MULTICAST_MessageHeader *msg
1044 = GNUNET_malloc (sizeof (*msg) + data_size);
1045
1046 msg->header.size = htons (sizeof (*msg) + data_size);
1047 msg->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE);
1048 msg->hop_counter = htonl ((uint32_t) sqlite3_column_int64 (stmt, 0));
1049 GNUNET_memcpy (&msg->signature,
1050 sqlite3_column_blob (stmt, 1),
1051 sqlite3_column_bytes (stmt, 1));
1052 GNUNET_memcpy (&msg->purpose,
1053 sqlite3_column_blob (stmt, 2),
1054 sqlite3_column_bytes (stmt, 2));
1055 msg->fragment_id = GNUNET_htonll (sqlite3_column_int64 (stmt, 3));
1056 msg->fragment_offset = GNUNET_htonll (sqlite3_column_int64 (stmt, 4));
1057 msg->message_id = GNUNET_htonll (sqlite3_column_int64 (stmt, 5));
1058 msg->group_generation = GNUNET_htonll (sqlite3_column_int64 (stmt, 6));
1059 msg->flags = htonl (sqlite3_column_int64 (stmt, 7));
1060 GNUNET_memcpy (&msg[1], sqlite3_column_blob (stmt, 9), data_size);
1061
1062 return cb (cb_cls, (void *) msg, sqlite3_column_int64 (stmt, 8));
1063}
1064
1065
1066static int
1067fragment_select (struct Plugin *plugin, sqlite3_stmt *stmt,
1068 uint64_t *returned_fragments,
1069 GNUNET_PSYCSTORE_FragmentCallback cb, void *cb_cls)
1070{
1071 int ret = GNUNET_SYSERR;
1072 int sql_ret;
1073
1074 do
1075 {
1076 sql_ret = sqlite3_step (stmt);
1077 switch (sql_ret)
1078 {
1079 case SQLITE_DONE:
1080 if (ret != GNUNET_OK)
1081 ret = GNUNET_NO;
1082 break;
1083 case SQLITE_ROW:
1084 ret = fragment_row (stmt, cb, cb_cls);
1085 (*returned_fragments)++;
1086 if (ret != GNUNET_YES)
1087 sql_ret = SQLITE_DONE;
1088 break;
1089 default:
1090 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1091 "sqlite3_step");
1092 }
1093 }
1094 while (sql_ret == SQLITE_ROW);
1095
1096 return ret;
1097}
1098
1099/**
1100 * Retrieve a message fragment range by fragment ID.
1101 *
1102 * @see GNUNET_PSYCSTORE_fragment_get()
1103 *
1104 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1105 */
1106static int
1107fragment_get (void *cls,
1108 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1109 uint64_t first_fragment_id,
1110 uint64_t last_fragment_id,
1111 uint64_t *returned_fragments,
1112 GNUNET_PSYCSTORE_FragmentCallback cb,
1113 void *cb_cls)
1114{
1115 struct Plugin *plugin = cls;
1116 sqlite3_stmt *stmt = plugin->select_fragments;
1117 int ret = GNUNET_SYSERR;
1118 *returned_fragments = 0;
1119
1120 if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key,
1121 sizeof (*channel_key),
1122 SQLITE_STATIC)
1123 || SQLITE_OK != sqlite3_bind_int64 (stmt, 2, first_fragment_id)
1124 || SQLITE_OK != sqlite3_bind_int64 (stmt, 3, last_fragment_id))
1125 {
1126 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1127 "sqlite3_bind");
1128 }
1129 else
1130 {
1131 ret = fragment_select (plugin, stmt, returned_fragments, cb, cb_cls);
1132 }
1133
1134 if (SQLITE_OK != sqlite3_reset (stmt))
1135 {
1136 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1137 "sqlite3_reset");
1138 }
1139
1140 return ret;
1141}
1142
1143
1144/**
1145 * Retrieve a message fragment range by fragment ID.
1146 *
1147 * @see GNUNET_PSYCSTORE_fragment_get_latest()
1148 *
1149 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1150 */
1151static int
1152fragment_get_latest (void *cls,
1153 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1154 uint64_t fragment_limit,
1155 uint64_t *returned_fragments,
1156 GNUNET_PSYCSTORE_FragmentCallback cb,
1157 void *cb_cls)
1158{
1159 struct Plugin *plugin = cls;
1160 sqlite3_stmt *stmt = plugin->select_latest_fragments;
1161 int ret = GNUNET_SYSERR;
1162 *returned_fragments = 0;
1163
1164 if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key,
1165 sizeof (*channel_key),
1166 SQLITE_STATIC)
1167 || SQLITE_OK != sqlite3_bind_int64 (stmt, 2, fragment_limit))
1168 {
1169 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1170 "sqlite3_bind");
1171 }
1172 else
1173 {
1174 ret = fragment_select (plugin, stmt, returned_fragments, cb, cb_cls);
1175 }
1176
1177 if (SQLITE_OK != sqlite3_reset (stmt))
1178 {
1179 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1180 "sqlite3_reset");
1181 }
1182
1183 return ret;
1184}
1185
1186
1187/**
1188 * Retrieve all fragments of a message ID range.
1189 *
1190 * @see GNUNET_PSYCSTORE_message_get()
1191 *
1192 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1193 */
1194static int
1195message_get (void *cls,
1196 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1197 uint64_t first_message_id,
1198 uint64_t last_message_id,
1199 uint64_t fragment_limit,
1200 uint64_t *returned_fragments,
1201 GNUNET_PSYCSTORE_FragmentCallback cb,
1202 void *cb_cls)
1203{
1204 struct Plugin *plugin = cls;
1205 sqlite3_stmt *stmt = plugin->select_messages;
1206 int ret = GNUNET_SYSERR;
1207 *returned_fragments = 0;
1208
1209 if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key,
1210 sizeof (*channel_key),
1211 SQLITE_STATIC)
1212 || SQLITE_OK != sqlite3_bind_int64 (stmt, 2, first_message_id)
1213 || SQLITE_OK != sqlite3_bind_int64 (stmt, 3, last_message_id)
1214 || SQLITE_OK != sqlite3_bind_int64 (stmt, 4,
1215 (0 != fragment_limit)
1216 ? fragment_limit
1217 : INT64_MAX))
1218 {
1219 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1220 "sqlite3_bind");
1221 }
1222 else
1223 {
1224 ret = fragment_select (plugin, stmt, returned_fragments, cb, cb_cls);
1225 }
1226
1227 if (SQLITE_OK != sqlite3_reset (stmt))
1228 {
1229 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1230 "sqlite3_reset");
1231 }
1232
1233 return ret;
1234}
1235
1236
1237/**
1238 * Retrieve all fragments of the latest messages.
1239 *
1240 * @see GNUNET_PSYCSTORE_message_get_latest()
1241 *
1242 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1243 */
1244static int
1245message_get_latest (void *cls,
1246 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1247 uint64_t message_limit,
1248 uint64_t *returned_fragments,
1249 GNUNET_PSYCSTORE_FragmentCallback cb,
1250 void *cb_cls)
1251{
1252 struct Plugin *plugin = cls;
1253 sqlite3_stmt *stmt = plugin->select_latest_messages;
1254 int ret = GNUNET_SYSERR;
1255 *returned_fragments = 0;
1256
1257 if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key,
1258 sizeof (*channel_key),
1259 SQLITE_STATIC)
1260 || SQLITE_OK != sqlite3_bind_blob (stmt, 2, channel_key,
1261 sizeof (*channel_key),
1262 SQLITE_STATIC)
1263 || SQLITE_OK != sqlite3_bind_int64 (stmt, 3, message_limit))
1264 {
1265 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1266 "sqlite3_bind");
1267 }
1268 else
1269 {
1270 ret = fragment_select (plugin, stmt, returned_fragments, cb, cb_cls);
1271 }
1272
1273 if (SQLITE_OK != sqlite3_reset (stmt))
1274 {
1275 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1276 "sqlite3_reset");
1277 }
1278
1279 return ret;
1280}
1281
1282
1283/**
1284 * Retrieve a fragment of message specified by its message ID and fragment
1285 * offset.
1286 *
1287 * @see GNUNET_PSYCSTORE_message_get_fragment()
1288 *
1289 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1290 */
1291static int
1292message_get_fragment (void *cls,
1293 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1294 uint64_t message_id,
1295 uint64_t fragment_offset,
1296 GNUNET_PSYCSTORE_FragmentCallback cb,
1297 void *cb_cls)
1298{
1299 struct Plugin *plugin = cls;
1300 sqlite3_stmt *stmt = plugin->select_message_fragment;
1301 int ret = GNUNET_SYSERR;
1302
1303 if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key,
1304 sizeof (*channel_key),
1305 SQLITE_STATIC)
1306 || SQLITE_OK != sqlite3_bind_int64 (stmt, 2, message_id)
1307 || SQLITE_OK != sqlite3_bind_int64 (stmt, 3, fragment_offset))
1308 {
1309 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1310 "sqlite3_bind");
1311 }
1312 else
1313 {
1314 switch (sqlite3_step (stmt))
1315 {
1316 case SQLITE_DONE:
1317 ret = GNUNET_NO;
1318 break;
1319 case SQLITE_ROW:
1320 ret = fragment_row (stmt, cb, cb_cls);
1321 break;
1322 default:
1323 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1324 "sqlite3_step");
1325 }
1326 }
1327
1328 if (SQLITE_OK != sqlite3_reset (stmt))
1329 {
1330 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1331 "sqlite3_reset");
1332 }
1333
1334 return ret;
1335}
1336
1337/**
1338 * Retrieve the max. values of message counters for a channel.
1339 *
1340 * @see GNUNET_PSYCSTORE_counters_get()
1341 *
1342 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1343 */
1344static int
1345counters_message_get (void *cls,
1346 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1347 uint64_t *max_fragment_id,
1348 uint64_t *max_message_id,
1349 uint64_t *max_group_generation)
1350{
1351 struct Plugin *plugin = cls;
1352 sqlite3_stmt *stmt = plugin->select_counters_message;
1353 int ret = GNUNET_SYSERR;
1354
1355 if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key,
1356 sizeof (*channel_key),
1357 SQLITE_STATIC))
1358 {
1359 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1360 "sqlite3_bind");
1361 }
1362 else
1363 {
1364 switch (sqlite3_step (stmt))
1365 {
1366 case SQLITE_DONE:
1367 ret = GNUNET_NO;
1368 break;
1369 case SQLITE_ROW:
1370 *max_fragment_id = sqlite3_column_int64 (stmt, 0);
1371 *max_message_id = sqlite3_column_int64 (stmt, 1);
1372 *max_group_generation = sqlite3_column_int64 (stmt, 2);
1373 ret = GNUNET_OK;
1374 break;
1375 default:
1376 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1377 "sqlite3_step");
1378 }
1379 }
1380
1381 if (SQLITE_OK != sqlite3_reset (stmt))
1382 {
1383 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1384 "sqlite3_reset");
1385 }
1386
1387 return ret;
1388}
1389
1390/**
1391 * Retrieve the max. values of state counters for a channel.
1392 *
1393 * @see GNUNET_PSYCSTORE_counters_get()
1394 *
1395 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1396 */
1397static int
1398counters_state_get (void *cls,
1399 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1400 uint64_t *max_state_message_id)
1401{
1402 struct Plugin *plugin = cls;
1403 sqlite3_stmt *stmt = plugin->select_counters_state;
1404 int ret = GNUNET_SYSERR;
1405
1406 if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key,
1407 sizeof (*channel_key),
1408 SQLITE_STATIC))
1409 {
1410 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1411 "sqlite3_bind");
1412 }
1413 else
1414 {
1415 switch (sqlite3_step (stmt))
1416 {
1417 case SQLITE_DONE:
1418 ret = GNUNET_NO;
1419 break;
1420 case SQLITE_ROW:
1421 *max_state_message_id = sqlite3_column_int64 (stmt, 0);
1422 ret = GNUNET_OK;
1423 break;
1424 default:
1425 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1426 "sqlite3_step");
1427 }
1428 }
1429
1430 if (SQLITE_OK != sqlite3_reset (stmt))
1431 {
1432 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1433 "sqlite3_reset");
1434 }
1435
1436 return ret;
1437}
1438
1439
1440/**
1441 * Assign a value to a state variable.
1442 *
1443 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1444 */
1445static int
1446state_assign (struct Plugin *plugin, sqlite3_stmt *stmt,
1447 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1448 const char *name, const void *value, size_t value_size)
1449{
1450 int ret = GNUNET_SYSERR;
1451
1452 if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key,
1453 sizeof (*channel_key), SQLITE_STATIC)
1454 || SQLITE_OK != sqlite3_bind_text (stmt, 2, name, -1, SQLITE_STATIC)
1455 || SQLITE_OK != sqlite3_bind_blob (stmt, 3, value, value_size,
1456 SQLITE_STATIC))
1457 {
1458 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1459 "sqlite3_bind");
1460 }
1461 else
1462 {
1463 switch (sqlite3_step (stmt))
1464 {
1465 case SQLITE_DONE:
1466 ret = 0 < sqlite3_total_changes (plugin->dbh) ? GNUNET_OK : GNUNET_NO;
1467 break;
1468 default:
1469 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1470 "sqlite3_step");
1471 }
1472 }
1473
1474 if (SQLITE_OK != sqlite3_reset (stmt))
1475 {
1476 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1477 "sqlite3_reset");
1478 return GNUNET_SYSERR;
1479 }
1480
1481 return ret;
1482}
1483
1484
1485static int
1486update_message_id (struct Plugin *plugin, sqlite3_stmt *stmt,
1487 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1488 uint64_t message_id)
1489{
1490 if (SQLITE_OK != sqlite3_bind_int64 (stmt, 1, message_id)
1491 || SQLITE_OK != sqlite3_bind_blob (stmt, 2, channel_key,
1492 sizeof (*channel_key), SQLITE_STATIC))
1493 {
1494 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1495 "sqlite3_bind");
1496 }
1497 else if (SQLITE_DONE != sqlite3_step (stmt))
1498 {
1499 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1500 "sqlite3_step");
1501 }
1502 if (SQLITE_OK != sqlite3_reset (stmt))
1503 {
1504 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1505 "sqlite3_reset");
1506 return GNUNET_SYSERR;
1507 }
1508 return GNUNET_OK;
1509}
1510
1511
1512/**
1513 * Begin modifying current state.
1514 */
1515static int
1516state_modify_begin (void *cls,
1517 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1518 uint64_t message_id, uint64_t state_delta)
1519{
1520 struct Plugin *plugin = cls;
1521
1522 if (state_delta > 0)
1523 {
1524 /**
1525 * We can only apply state modifiers in the current message if modifiers in
1526 * the previous stateful message (message_id - state_delta) were already
1527 * applied.
1528 */
1529
1530 uint64_t max_state_message_id = 0;
1531 int ret = counters_state_get (plugin, channel_key, &max_state_message_id);
1532 switch (ret)
1533 {
1534 case GNUNET_OK:
1535 case GNUNET_NO: // no state yet
1536 ret = GNUNET_OK;
1537 break;
1538 default:
1539 return ret;
1540 }
1541
1542 if (max_state_message_id < message_id - state_delta)
1543 return GNUNET_NO; /* some stateful messages not yet applied */
1544 else if (message_id - state_delta < max_state_message_id)
1545 return GNUNET_NO; /* changes already applied */
1546 }
1547
1548 if (TRANSACTION_NONE != plugin->transaction)
1549 {
1550 /** @todo FIXME: wait for other transaction to finish */
1551 return GNUNET_SYSERR;
1552 }
1553 return transaction_begin (plugin, TRANSACTION_STATE_MODIFY);
1554}
1555
1556
1557/**
1558 * Set the current value of state variable.
1559 *
1560 * @see GNUNET_PSYCSTORE_state_modify()
1561 *
1562 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1563 */
1564static int
1565state_modify_op (void *cls,
1566 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1567 enum GNUNET_PSYC_Operator op,
1568 const char *name, const void *value, size_t value_size)
1569{
1570 struct Plugin *plugin = cls;
1571 GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction);
1572
1573 switch (op)
1574 {
1575 case GNUNET_PSYC_OP_ASSIGN:
1576 return state_assign (plugin, plugin->insert_state_current, channel_key,
1577 name, value, value_size);
1578
1579 default: /** @todo implement more state operations */
1580 GNUNET_break (0);
1581 return GNUNET_SYSERR;
1582 }
1583}
1584
1585
1586/**
1587 * End modifying current state.
1588 */
1589static int
1590state_modify_end (void *cls,
1591 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1592 uint64_t message_id)
1593{
1594 struct Plugin *plugin = cls;
1595 GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction);
1596
1597 return
1598 GNUNET_OK == exec_channel (plugin, plugin->delete_state_empty, channel_key)
1599 && GNUNET_OK == update_message_id (plugin,
1600 plugin->update_max_state_message_id,
1601 channel_key, message_id)
1602 && GNUNET_OK == transaction_commit (plugin)
1603 ? GNUNET_OK : GNUNET_SYSERR;
1604}
1605
1606
1607/**
1608 * Begin state synchronization.
1609 */
1610static int
1611state_sync_begin (void *cls,
1612 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
1613{
1614 struct Plugin *plugin = cls;
1615 return exec_channel (plugin, plugin->delete_state_sync, channel_key);
1616}
1617
1618
1619/**
1620 * Assign current value of a state variable.
1621 *
1622 * @see GNUNET_PSYCSTORE_state_modify()
1623 *
1624 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1625 */
1626static int
1627state_sync_assign (void *cls,
1628 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1629 const char *name, const void *value, size_t value_size)
1630{
1631 struct Plugin *plugin = cls;
1632 return state_assign (cls, plugin->insert_state_sync, channel_key,
1633 name, value, value_size);
1634}
1635
1636
1637/**
1638 * End modifying current state.
1639 */
1640static int
1641state_sync_end (void *cls,
1642 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1643 uint64_t max_state_message_id,
1644 uint64_t state_hash_message_id)
1645{
1646 struct Plugin *plugin = cls;
1647 int ret = GNUNET_SYSERR;
1648
1649 if (TRANSACTION_NONE != plugin->transaction)
1650 {
1651 /** @todo FIXME: wait for other transaction to finish */
1652 return GNUNET_SYSERR;
1653 }
1654
1655 GNUNET_OK == transaction_begin (plugin, TRANSACTION_STATE_SYNC)
1656 && GNUNET_OK == exec_channel (plugin, plugin->delete_state, channel_key)
1657 && GNUNET_OK == exec_channel (plugin, plugin->insert_state_from_sync,
1658 channel_key)
1659 && GNUNET_OK == exec_channel (plugin, plugin->delete_state_sync,
1660 channel_key)
1661 && GNUNET_OK == update_message_id (plugin,
1662 plugin->update_state_hash_message_id,
1663 channel_key, state_hash_message_id)
1664 && GNUNET_OK == update_message_id (plugin,
1665 plugin->update_max_state_message_id,
1666 channel_key, max_state_message_id)
1667 && GNUNET_OK == transaction_commit (plugin)
1668 ? ret = GNUNET_OK
1669 : transaction_rollback (plugin);
1670 return ret;
1671}
1672
1673
1674/**
1675 * Delete the whole state.
1676 *
1677 * @see GNUNET_PSYCSTORE_state_reset()
1678 *
1679 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1680 */
1681static int
1682state_reset (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
1683{
1684 struct Plugin *plugin = cls;
1685 return exec_channel (plugin, plugin->delete_state, channel_key);
1686}
1687
1688
1689/**
1690 * Update signed values of state variables in the state store.
1691 *
1692 * @see GNUNET_PSYCSTORE_state_hash_update()
1693 *
1694 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1695 */
1696static int
1697state_update_signed (void *cls,
1698 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
1699{
1700 struct Plugin *plugin = cls;
1701 return exec_channel (plugin, plugin->update_state_signed, channel_key);
1702}
1703
1704
1705/**
1706 * Retrieve a state variable by name.
1707 *
1708 * @see GNUNET_PSYCSTORE_state_get()
1709 *
1710 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1711 */
1712static int
1713state_get (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1714 const char *name, GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls)
1715{
1716 struct Plugin *plugin = cls;
1717 int ret = GNUNET_SYSERR;
1718
1719 sqlite3_stmt *stmt = plugin->select_state_one;
1720
1721 if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key,
1722 sizeof (*channel_key),
1723 SQLITE_STATIC)
1724 || SQLITE_OK != sqlite3_bind_text (stmt, 2, name, -1, SQLITE_STATIC))
1725 {
1726 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1727 "sqlite3_bind");
1728 }
1729 else
1730 {
1731 switch (sqlite3_step (stmt))
1732 {
1733 case SQLITE_DONE:
1734 ret = GNUNET_NO;
1735 break;
1736 case SQLITE_ROW:
1737 ret = cb (cb_cls, name, sqlite3_column_blob (stmt, 0),
1738 sqlite3_column_bytes (stmt, 0));
1739 break;
1740 default:
1741 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1742 "sqlite3_step");
1743 }
1744 }
1745
1746 if (SQLITE_OK != sqlite3_reset (stmt))
1747 {
1748 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1749 "sqlite3_reset");
1750 }
1751
1752 return ret;
1753}
1754
1755
1756/**
1757 * Retrieve all state variables for a channel with the given prefix.
1758 *
1759 * @see GNUNET_PSYCSTORE_state_get_prefix()
1760 *
1761 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1762 */
1763static int
1764state_get_prefix (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1765 const char *name, GNUNET_PSYCSTORE_StateCallback cb,
1766 void *cb_cls)
1767{
1768 struct Plugin *plugin = cls;
1769 int ret = GNUNET_SYSERR;
1770 sqlite3_stmt *stmt = plugin->select_state_prefix;
1771 size_t name_len = strlen (name);
1772
1773 if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key,
1774 sizeof (*channel_key), SQLITE_STATIC)
1775 || SQLITE_OK != sqlite3_bind_text (stmt, 2, name, name_len, SQLITE_STATIC)
1776 || SQLITE_OK != sqlite3_bind_int (stmt, 3, name_len)
1777 || SQLITE_OK != sqlite3_bind_text (stmt, 4, name, name_len, SQLITE_STATIC))
1778 {
1779 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1780 "sqlite3_bind");
1781 }
1782 else
1783 {
1784 int sql_ret;
1785 do
1786 {
1787 sql_ret = sqlite3_step (stmt);
1788 switch (sql_ret)
1789 {
1790 case SQLITE_DONE:
1791 if (ret != GNUNET_OK)
1792 ret = GNUNET_NO;
1793 break;
1794 case SQLITE_ROW:
1795 ret = cb (cb_cls, (const char *) sqlite3_column_text (stmt, 0),
1796 sqlite3_column_blob (stmt, 1),
1797 sqlite3_column_bytes (stmt, 1));
1798 if (ret != GNUNET_YES)
1799 sql_ret = SQLITE_DONE;
1800 break;
1801 default:
1802 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1803 "sqlite3_step");
1804 }
1805 }
1806 while (sql_ret == SQLITE_ROW);
1807 }
1808 if (SQLITE_OK != sqlite3_reset (stmt))
1809 {
1810 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1811 "sqlite3_reset");
1812 }
1813 return ret;
1814}
1815
1816
1817/**
1818 * Retrieve all signed state variables for a channel.
1819 *
1820 * @see GNUNET_PSYCSTORE_state_get_signed()
1821 *
1822 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1823 */
1824static int
1825state_get_signed (void *cls,
1826 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1827 GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls)
1828{
1829 struct Plugin *plugin = cls;
1830 int ret = GNUNET_SYSERR;
1831
1832 sqlite3_stmt *stmt = plugin->select_state_signed;
1833
1834 if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key,
1835 sizeof (*channel_key), SQLITE_STATIC))
1836 {
1837 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1838 "sqlite3_bind");
1839 }
1840 else
1841 {
1842 int sql_ret;
1843 do
1844 {
1845 sql_ret = sqlite3_step (stmt);
1846 switch (sql_ret)
1847 {
1848 case SQLITE_DONE:
1849 if (ret != GNUNET_OK)
1850 ret = GNUNET_NO;
1851 break;
1852 case SQLITE_ROW:
1853 ret = cb (cb_cls, (const char *) sqlite3_column_text (stmt, 0),
1854 sqlite3_column_blob (stmt, 1),
1855 sqlite3_column_bytes (stmt, 1));
1856 if (ret != GNUNET_YES)
1857 sql_ret = SQLITE_DONE;
1858 break;
1859 default:
1860 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1861 "sqlite3_step");
1862 }
1863 }
1864 while (sql_ret == SQLITE_ROW);
1865 }
1866
1867 if (SQLITE_OK != sqlite3_reset (stmt))
1868 {
1869 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1870 "sqlite3_reset");
1871 }
1872
1873 return ret;
1874}
1875
1876
1877/**
1878 * Entry point for the plugin.
1879 *
1880 * @param cls The struct GNUNET_CONFIGURATION_Handle.
1881 * @return NULL on error, otherwise the plugin context
1882 */
1883void *
1884libgnunet_plugin_psycstore_sqlite_init (void *cls)
1885{
1886 static struct Plugin plugin;
1887 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
1888 struct GNUNET_PSYCSTORE_PluginFunctions *api;
1889
1890 if (NULL != plugin.cfg)
1891 return NULL; /* can only initialize once! */
1892 memset (&plugin, 0, sizeof (struct Plugin));
1893 plugin.cfg = cfg;
1894 if (GNUNET_OK != database_setup (&plugin))
1895 {
1896 database_shutdown (&plugin);
1897 return NULL;
1898 }
1899 api = GNUNET_new (struct GNUNET_PSYCSTORE_PluginFunctions);
1900 api->cls = &plugin;
1901 api->membership_store = &sqlite_membership_store;
1902 api->membership_test = &membership_test;
1903 api->fragment_store = &fragment_store;
1904 api->message_add_flags = &message_add_flags;
1905 api->fragment_get = &fragment_get;
1906 api->fragment_get_latest = &fragment_get_latest;
1907 api->message_get = &message_get;
1908 api->message_get_latest = &message_get_latest;
1909 api->message_get_fragment = &message_get_fragment;
1910 api->counters_message_get = &counters_message_get;
1911 api->counters_state_get = &counters_state_get;
1912 api->state_modify_begin = &state_modify_begin;
1913 api->state_modify_op = &state_modify_op;
1914 api->state_modify_end = &state_modify_end;
1915 api->state_sync_begin = &state_sync_begin;
1916 api->state_sync_assign = &state_sync_assign;
1917 api->state_sync_end = &state_sync_end;
1918 api->state_reset = &state_reset;
1919 api->state_update_signed = &state_update_signed;
1920 api->state_get = &state_get;
1921 api->state_get_prefix = &state_get_prefix;
1922 api->state_get_signed = &state_get_signed;
1923
1924 LOG (GNUNET_ERROR_TYPE_INFO, _("SQLite database running\n"));
1925 return api;
1926}
1927
1928
1929/**
1930 * Exit point from the plugin.
1931 *
1932 * @param cls The plugin context (as returned by "init")
1933 * @return Always NULL
1934 */
1935void *
1936libgnunet_plugin_psycstore_sqlite_done (void *cls)
1937{
1938 struct GNUNET_PSYCSTORE_PluginFunctions *api = cls;
1939 struct Plugin *plugin = api->cls;
1940
1941 database_shutdown (plugin);
1942 plugin->cfg = NULL;
1943 GNUNET_free (api);
1944 LOG (GNUNET_ERROR_TYPE_DEBUG, "SQLite plugin is finished\n");
1945 return NULL;
1946}
1947
1948/* 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 @@
1[psycstore]
2START_ON_DEMAND = @START_ON_DEMAND@
3BINARY = gnunet-service-psycstore
4
5UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-psycstore.sock
6UNIX_MATCH_UID = YES
7UNIX_MATCH_GID = YES
8
9@UNIXONLY@PORT = 2111
10HOSTNAME = localhost
11ACCEPT_FROM = 127.0.0.1;
12ACCEPT_FROM6 = ::1;
13
14DATABASE = sqlite
15
16[psycstore-sqlite]
17FILENAME = $GNUNET_DATA_HOME/psycstore/sqlite.db
18
19[psycstore-mysql]
20DATABASE = gnunet
21CONFIG = ~/.my.cnf
22# USER = gnunet
23# PASSWORD =
24# HOST = localhost
25# PORT = 3306
26
27[psycstore-postgres]
28CONFIG = 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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file psycstore/psycstore.h
23 * @brief Common type definitions for the PSYCstore service and API.
24 * @author Gabor X Toth
25 */
26
27#ifndef GNUNET_PSYCSTORE_H
28#define GNUNET_PSYCSTORE_H
29
30#include "gnunet_common.h"
31
32
33GNUNET_NETWORK_STRUCT_BEGIN
34
35/**
36 * Answer from service to client about last operation.
37 */
38struct OperationResult
39{
40 /**
41 * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE
42 */
43 struct GNUNET_MessageHeader header;
44
45 uint32_t reserved GNUNET_PACKED;
46
47 /**
48 * Operation ID.
49 */
50 uint64_t op_id GNUNET_PACKED;
51
52 /**lowed by
53 * Status code for the operation.
54 */
55 uint64_t result_code GNUNET_PACKED;
56
57 /* followed by 0-terminated error message (on error) */
58
59};
60
61
62/**
63 * Answer from service to client about master counters.
64 *
65 * @see GNUNET_PSYCSTORE_counters_get()
66 */
67struct CountersResult
68{
69 /**
70 * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_COUNTERS
71 */
72 struct GNUNET_MessageHeader header;
73
74 /**
75 * Status code for the operation:
76 * #GNUNET_OK: success, counter values are returned.
77 * #GNUNET_NO: no message has been sent to the channel yet.
78 * #GNUNET_SYSERR: an error occurred.
79 */
80 uint32_t result_code GNUNET_PACKED;
81
82 /**
83 * Operation ID.
84 */
85 uint64_t op_id GNUNET_PACKED;
86
87 uint64_t max_fragment_id GNUNET_PACKED;
88
89 uint64_t max_message_id GNUNET_PACKED;
90
91 uint64_t max_group_generation GNUNET_PACKED;
92
93 uint64_t max_state_message_id GNUNET_PACKED;
94};
95
96
97/**
98 * Answer from service to client containing a message fragment.
99 */
100struct FragmentResult
101{
102 /**
103 * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE
104 */
105 struct GNUNET_MessageHeader header;
106
107 uint32_t psycstore_flags GNUNET_PACKED;
108
109 /**
110 * Operation ID.
111 */
112 uint64_t op_id GNUNET_PACKED;
113
114 /* Followed by GNUNET_MULTICAST_MessageHeader */
115};
116
117
118/**
119 * Answer from service to client containing a state variable.
120 */
121struct StateResult
122{
123 /**
124 * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE
125 */
126 struct GNUNET_MessageHeader header;
127
128 uint16_t name_size GNUNET_PACKED;
129
130 uint16_t reserved GNUNET_PACKED;
131
132 /**
133 * Operation ID.
134 */
135 uint64_t op_id GNUNET_PACKED;
136
137 /* Followed by name and value */
138};
139
140
141/**
142 * Generic operation request.
143 */
144struct OperationRequest
145{
146 struct GNUNET_MessageHeader header;
147
148 uint32_t reserved GNUNET_PACKED;
149
150 /**
151 * Operation ID.
152 */
153 uint64_t op_id GNUNET_PACKED;
154
155 struct GNUNET_CRYPTO_EddsaPublicKey channel_key;
156};
157
158
159/**
160 * @see GNUNET_PSYCSTORE_membership_store()
161 */
162struct MembershipStoreRequest
163{
164 /**
165 * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_STORE
166 */
167 struct GNUNET_MessageHeader header;
168
169 uint32_t reserved GNUNET_PACKED;
170
171 /**
172 * Operation ID.
173 */
174 uint64_t op_id GNUNET_PACKED;
175
176 /**
177 * Channel's public key.
178 */
179 struct GNUNET_CRYPTO_EddsaPublicKey channel_key;
180
181 /**
182 * Slave's public key.
183 */
184 struct GNUNET_CRYPTO_EcdsaPublicKey slave_key;
185
186 uint64_t announced_at GNUNET_PACKED;
187 uint64_t effective_since GNUNET_PACKED;
188 uint64_t group_generation GNUNET_PACKED;
189 uint8_t did_join;
190};
191
192
193/**
194 * @see GNUNET_PSYCSTORE_membership_test()
195 */
196struct MembershipTestRequest
197{
198 /**
199 * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_TEST
200 */
201 struct GNUNET_MessageHeader header;
202
203 uint32_t reserved GNUNET_PACKED;
204
205 /**
206 * Operation ID.
207 */
208 uint64_t op_id GNUNET_PACKED;
209
210 /**
211 * Channel's public key.
212 */
213 struct GNUNET_CRYPTO_EddsaPublicKey channel_key;
214
215 /**
216 * Slave's public key.
217 */
218 struct GNUNET_CRYPTO_EcdsaPublicKey slave_key;
219
220 uint64_t message_id GNUNET_PACKED;
221
222 uint64_t group_generation GNUNET_PACKED;
223};
224
225
226/**
227 * @see GNUNET_PSYCSTORE_fragment_store()
228 */
229struct FragmentStoreRequest
230{
231 /**
232 * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_STORE
233 */
234 struct GNUNET_MessageHeader header;
235
236 /**
237 * enum GNUNET_PSYCSTORE_MessageFlags
238 */
239 uint32_t psycstore_flags GNUNET_PACKED;
240
241 /**
242 * Channel's public key.
243 */
244 struct GNUNET_CRYPTO_EddsaPublicKey channel_key;
245
246 /**
247 * Operation ID.
248 */
249 uint64_t op_id;
250
251 /* Followed by fragment */
252};
253
254
255/**
256 * @see GNUNET_PSYCSTORE_fragment_get()
257 */
258struct FragmentGetRequest
259{
260 /**
261 * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_GET
262 */
263 struct GNUNET_MessageHeader header;
264
265 uint32_t reserved GNUNET_PACKED;
266
267 /**
268 * Operation ID.
269 */
270 uint64_t op_id GNUNET_PACKED;
271
272 /**
273 * Channel's public key.
274 */
275 struct GNUNET_CRYPTO_EddsaPublicKey channel_key;
276
277 /**
278 * Slave's public key.
279 */
280 struct GNUNET_CRYPTO_EcdsaPublicKey slave_key;
281
282 /**
283 * First fragment ID to request.
284 */
285 uint64_t first_fragment_id GNUNET_PACKED;
286
287 /**
288 * Last fragment ID to request.
289 */
290 uint64_t last_fragment_id GNUNET_PACKED;
291
292 /**
293 * Maximum number of fragments to retrieve.
294 */
295 uint64_t fragment_limit GNUNET_PACKED;
296
297 /**
298 * Do membership test with @a slave_key before returning fragment?
299 * #GNUNET_YES or #GNUNET_NO
300 */
301 uint8_t do_membership_test;
302};
303
304
305/**
306 * @see GNUNET_PSYCSTORE_message_get()
307 */
308struct MessageGetRequest
309{
310 /**
311 * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET
312 */
313 struct GNUNET_MessageHeader header;
314
315 uint32_t reserved GNUNET_PACKED;
316
317 /**
318 * Operation ID.
319 */
320 uint64_t op_id GNUNET_PACKED;
321
322 /**
323 * Channel's public key.
324 */
325 struct GNUNET_CRYPTO_EddsaPublicKey channel_key;
326
327 /**
328 * Slave's public key.
329 */
330 struct GNUNET_CRYPTO_EcdsaPublicKey slave_key;
331
332 /**
333 * First message ID to request.
334 */
335 uint64_t first_message_id GNUNET_PACKED;
336
337 /**
338 * Last message ID to request.
339 */
340 uint64_t last_message_id GNUNET_PACKED;
341
342 /**
343 * Maximum number of messages to retrieve.
344 */
345 uint64_t message_limit GNUNET_PACKED;
346
347 /**
348 * Maximum number of fragments to retrieve.
349 */
350 uint64_t fragment_limit GNUNET_PACKED;
351
352 /**
353 * Do membership test with @a slave_key before returning fragment?
354 * #GNUNET_YES or #GNUNET_NO
355 */
356 uint8_t do_membership_test;
357
358 /* Followed by method_prefix */
359};
360
361
362/**
363 * @see GNUNET_PSYCSTORE_message_get_fragment()
364 */
365struct MessageGetFragmentRequest
366{
367 /**
368 * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_FRAGMENT_GET
369 */
370 struct GNUNET_MessageHeader header;
371
372 uint32_t reserved GNUNET_PACKED;
373
374 /**
375 * Operation ID.
376 */
377 uint64_t op_id GNUNET_PACKED;
378
379 /**
380 * Channel's public key.
381 */
382 struct GNUNET_CRYPTO_EddsaPublicKey channel_key;
383
384 /**
385 * Slave's public key.
386 */
387 struct GNUNET_CRYPTO_EcdsaPublicKey slave_key;
388
389 /**
390 * Requested message ID.
391 */
392 uint64_t message_id GNUNET_PACKED;
393
394 /**
395 * Requested fragment offset.
396 */
397 uint64_t fragment_offset GNUNET_PACKED;
398
399 /**
400 * Do membership test with @a slave_key before returning fragment?
401 * #GNUNET_YES or #GNUNET_NO
402 */
403 uint8_t do_membership_test;
404};
405
406
407/**
408 * @see GNUNET_PSYCSTORE_state_hash_update()
409 */
410struct StateHashUpdateRequest
411{
412 /**
413 * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_HASH_UPDATE
414 */
415 struct GNUNET_MessageHeader header;
416
417 uint32_t reserved GNUNET_PACKED;
418
419 /**
420 * Operation ID.
421 */
422 uint64_t op_id GNUNET_PACKED;
423
424 /**
425 * Channel's public key.
426 */
427 struct GNUNET_CRYPTO_EddsaPublicKey channel_key;
428
429 struct GNUNET_HashCode hash;
430};
431
432
433enum StateOpFlags
434{
435 STATE_OP_FIRST = 1 << 0,
436 STATE_OP_LAST = 1 << 1
437};
438
439
440/**
441 * @see GNUNET_PSYCSTORE_state_modify()
442 */
443struct StateModifyRequest
444{
445 /**
446 * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_MODIFY
447 */
448 struct GNUNET_MessageHeader header;
449
450 /**
451 * Operation ID.
452 */
453 uint64_t op_id GNUNET_PACKED;
454
455 /**
456 * ID of the message to apply the state changes in.
457 */
458 uint64_t message_id GNUNET_PACKED;
459
460 /**
461 * State delta of the message with ID @a message_id.
462 */
463 uint64_t state_delta GNUNET_PACKED;
464
465 /**
466 * Channel's public key.
467 */
468 struct GNUNET_CRYPTO_EddsaPublicKey channel_key;
469};
470
471
472/**
473 * @see GNUNET_PSYCSTORE_state_sync()
474 */
475struct StateSyncRequest
476{
477 /**
478 * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_SYNC
479 */
480 struct GNUNET_MessageHeader header;
481
482 /**
483 * Size of name, including NUL terminator.
484 */
485 uint16_t name_size GNUNET_PACKED;
486
487 /**
488 * OR'd StateOpFlags
489 */
490 uint8_t flags;
491
492 uint8_t reserved;
493
494 /**
495 * Operation ID.
496 */
497 uint64_t op_id GNUNET_PACKED;
498
499 /**
500 * ID of the message that contains the state_hash PSYC header variable.
501 */
502 uint64_t state_hash_message_id GNUNET_PACKED;
503
504 /**
505 * ID of the last stateful message before @a state_hash_message_id.
506 */
507 uint64_t max_state_message_id GNUNET_PACKED;
508
509 /**
510 * Channel's public key.
511 */
512 struct GNUNET_CRYPTO_EddsaPublicKey channel_key;
513
514 /* Followed by NUL-terminated name, then the value. */
515};
516
517
518GNUNET_NETWORK_STRUCT_END
519
520#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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file psycstore/psycstore_api.c
23 * @brief API to interact with the PSYCstore service
24 * @author Gabor X Toth
25 * @author Christian Grothoff
26 */
27
28#include <inttypes.h>
29
30#include "platform.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_constants.h"
33#include "gnunet_protocols.h"
34#include "gnunet_psycstore_service.h"
35#include "gnunet_multicast_service.h"
36#include "psycstore.h"
37
38#define LOG(kind,...) GNUNET_log_from (kind, "psycstore-api",__VA_ARGS__)
39
40/**
41 * Handle for an operation with the PSYCstore service.
42 */
43struct GNUNET_PSYCSTORE_OperationHandle
44{
45
46 /**
47 * Main PSYCstore handle.
48 */
49 struct GNUNET_PSYCSTORE_Handle *h;
50
51 /**
52 * Data callbacks.
53 */
54 union {
55 GNUNET_PSYCSTORE_FragmentCallback fragment_cb;
56 GNUNET_PSYCSTORE_CountersCallback counters_cb;
57 GNUNET_PSYCSTORE_StateCallback state_cb;
58 };
59
60 /**
61 * Closure for callbacks.
62 */
63 void *cls;
64
65 /**
66 * Message envelope.
67 */
68 struct GNUNET_MQ_Envelope *env;
69
70 /**
71 * Operation ID.
72 */
73 uint64_t op_id;
74};
75
76
77/**
78 * Handle for the service.
79 */
80struct GNUNET_PSYCSTORE_Handle
81{
82 /**
83 * Configuration to use.
84 */
85 const struct GNUNET_CONFIGURATION_Handle *cfg;
86
87 /**
88 * Client connection.
89 */
90 struct GNUNET_MQ_Handle *mq;
91
92 /**
93 * Async operations.
94 */
95 struct GNUNET_OP_Handle *op;
96
97 /**
98 * Task doing exponential back-off trying to reconnect.
99 */
100 struct GNUNET_SCHEDULER_Task *reconnect_task;
101
102 /**
103 * Delay for next connect retry.
104 */
105 struct GNUNET_TIME_Relative reconnect_delay;
106
107
108 GNUNET_PSYCSTORE_FragmentCallback *fragment_cb;
109
110 GNUNET_PSYCSTORE_CountersCallback *counters_cb;
111
112 GNUNET_PSYCSTORE_StateCallback *state_cb;
113 /**
114 * Closure for callbacks.
115 */
116 void *cb_cls;
117};
118
119
120static int
121check_result_code (void *cls, const struct OperationResult *opres)
122{
123 uint16_t size = ntohs (opres->header.size);
124 const char *str = (const char *) &opres[1];
125 if ( (sizeof (*opres) < size) &&
126 ('\0' != str[size - sizeof (*opres) - 1]) )
127 {
128 GNUNET_break (0);
129 return GNUNET_SYSERR;
130 }
131
132 return GNUNET_OK;
133}
134
135
136static void
137handle_result_code (void *cls, const struct OperationResult *opres)
138{
139 struct GNUNET_PSYCSTORE_Handle *h = cls;
140 struct GNUNET_PSYCSTORE_OperationHandle *op = NULL;
141 uint16_t size = ntohs (opres->header.size);
142
143 const char *
144 str = (sizeof (*opres) < size) ? (const char *) &opres[1] : "";
145
146 if (GNUNET_YES == GNUNET_OP_result (h->op, GNUNET_ntohll (opres->op_id),
147 GNUNET_ntohll (opres->result_code) + INT64_MIN,
148 str, size - sizeof (*opres), (void **) &op))
149 {
150 LOG (GNUNET_ERROR_TYPE_DEBUG,
151 "handle_result_code: Received result message with OP ID: %" PRIu64 "\n",
152 GNUNET_ntohll (opres->op_id));
153 GNUNET_free (op);
154 }
155 else
156 {
157 LOG (GNUNET_ERROR_TYPE_DEBUG,
158 "handle_result_code: No callback registered for OP ID %" PRIu64 ".\n",
159 GNUNET_ntohll (opres->op_id));
160 }
161 h->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
162}
163
164
165static void
166handle_result_counters (void *cls, const struct CountersResult *cres)
167{
168 struct GNUNET_PSYCSTORE_Handle *h = cls;
169 struct GNUNET_PSYCSTORE_OperationHandle *op = NULL;
170
171 if (GNUNET_YES == GNUNET_OP_get (h->op, GNUNET_ntohll (cres->op_id),
172 NULL, NULL, (void **) &op))
173 {
174 GNUNET_assert (NULL != op);
175 if (NULL != op->counters_cb)
176 {
177 op->counters_cb (op->cls,
178 ntohl (cres->result_code),
179 GNUNET_ntohll (cres->max_fragment_id),
180 GNUNET_ntohll (cres->max_message_id),
181 GNUNET_ntohll (cres->max_group_generation),
182 GNUNET_ntohll (cres->max_state_message_id));
183 }
184 GNUNET_OP_remove (h->op, GNUNET_ntohll (cres->op_id));
185 GNUNET_free (op);
186 }
187 else
188 {
189 LOG (GNUNET_ERROR_TYPE_DEBUG,
190 "handle_result_counters: No callback registered for OP ID %" PRIu64 ".\n",
191 GNUNET_ntohll (cres->op_id));
192 }
193 h->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
194}
195
196
197static int
198check_result_fragment (void *cls, const struct FragmentResult *fres)
199{
200 uint16_t size = ntohs (fres->header.size);
201 struct GNUNET_MULTICAST_MessageHeader *mmsg =
202 (struct GNUNET_MULTICAST_MessageHeader *) &fres[1];
203 if (sizeof (*fres) + sizeof (*mmsg) < size
204 && sizeof (*fres) + ntohs (mmsg->header.size) != size)
205 {
206 LOG (GNUNET_ERROR_TYPE_ERROR,
207 "check_result_fragment: Received message with invalid length %lu bytes.\n",
208 size, sizeof (*fres));
209 GNUNET_break (0);
210 return GNUNET_SYSERR;
211 }
212 return GNUNET_OK;
213}
214
215
216static void
217handle_result_fragment (void *cls, const struct FragmentResult *fres)
218{
219 struct GNUNET_PSYCSTORE_Handle *h = cls;
220 struct GNUNET_PSYCSTORE_OperationHandle *op = NULL;
221
222 if (GNUNET_YES == GNUNET_OP_get (h->op, GNUNET_ntohll (fres->op_id),
223 NULL, NULL, (void **) &op))
224 {
225 GNUNET_assert (NULL != op);
226 if (NULL != op->fragment_cb)
227 op->fragment_cb (op->cls,
228 (struct GNUNET_MULTICAST_MessageHeader *) &fres[1],
229 ntohl (fres->psycstore_flags));
230 //GNUNET_OP_remove (h->op, GNUNET_ntohll (fres->op_id));
231 //GNUNET_free (op);
232 }
233 else
234 {
235 LOG (GNUNET_ERROR_TYPE_DEBUG,
236 "handle_result_fragment: No callback registered for OP ID %" PRIu64 ".\n",
237 GNUNET_ntohll (fres->op_id));
238 }
239 h->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
240}
241
242
243static int
244check_result_state (void *cls, const struct StateResult *sres)
245{
246 const char *name = (const char *) &sres[1];
247 uint16_t size = ntohs (sres->header.size);
248 uint16_t name_size = ntohs (sres->name_size);
249
250 if (name_size <= 2
251 || size - sizeof (*sres) < name_size
252 || '\0' != name[name_size - 1])
253 {
254 LOG (GNUNET_ERROR_TYPE_ERROR,
255 "check_result_state: Received state result message with invalid name.\n");
256 GNUNET_break (0);
257 return GNUNET_SYSERR;
258 }
259 return GNUNET_OK;
260}
261
262
263static void
264handle_result_state (void *cls, const struct StateResult *sres)
265{
266 struct GNUNET_PSYCSTORE_Handle *h = cls;
267 struct GNUNET_PSYCSTORE_OperationHandle *op = NULL;
268
269 const char *name = (const char *) &sres[1];
270 uint16_t name_size = ntohs (sres->name_size);
271
272 if (GNUNET_YES == GNUNET_OP_get (h->op, GNUNET_ntohll (sres->op_id),
273 NULL, NULL, (void **) &op))
274 {
275 GNUNET_assert (NULL != op);
276 if (NULL != op->state_cb)
277 op->state_cb (op->cls, name, (char *) &sres[1] + name_size,
278 ntohs (sres->header.size) - sizeof (*sres) - name_size);
279 //GNUNET_OP_remove (h->op, GNUNET_ntohll (sres->op_id));
280 //GNUNET_free (op);
281 }
282 else
283 {
284 LOG (GNUNET_ERROR_TYPE_DEBUG,
285 "handle_result_state: No callback registered for OP ID %" PRIu64 ".\n",
286 GNUNET_ntohll (sres->op_id));
287 }
288 h->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
289}
290
291
292static void
293reconnect (void *cls);
294
295
296/**
297 * Client disconnected from service.
298 *
299 * Reconnect after backoff period.=
300 */
301static void
302disconnected (void *cls, enum GNUNET_MQ_Error error)
303{
304 struct GNUNET_PSYCSTORE_Handle *h = cls;
305
306 LOG (GNUNET_ERROR_TYPE_DEBUG,
307 "Origin client disconnected (%d), re-connecting\n",
308 (int) error);
309 if (NULL != h->mq)
310 {
311 GNUNET_MQ_destroy (h->mq);
312 GNUNET_OP_destroy (h->op);
313 h->mq = NULL;
314 h->op = NULL;
315 }
316
317 h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
318 &reconnect, h);
319 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
320}
321
322
323static void
324do_connect (struct GNUNET_PSYCSTORE_Handle *h)
325{
326 LOG (GNUNET_ERROR_TYPE_DEBUG,
327 "Connecting to PSYCstore service.\n");
328
329 struct GNUNET_MQ_MessageHandler handlers[] = {
330 GNUNET_MQ_hd_var_size (result_code,
331 GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE,
332 struct OperationResult,
333 h),
334 GNUNET_MQ_hd_fixed_size (result_counters,
335 GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_COUNTERS,
336 struct CountersResult,
337 h),
338 GNUNET_MQ_hd_var_size (result_fragment,
339 GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_FRAGMENT,
340 struct FragmentResult,
341 h),
342 GNUNET_MQ_hd_var_size (result_state,
343 GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_STATE,
344 struct StateResult,
345 h),
346 GNUNET_MQ_handler_end ()
347 };
348
349 h->op = GNUNET_OP_create ();
350 GNUNET_assert (NULL == h->mq);
351 h->mq = GNUNET_CLIENT_connect (h->cfg, "psycstore",
352 handlers, disconnected, h);
353 GNUNET_assert (NULL != h->mq);
354}
355
356
357/**
358 * Try again to connect to the PSYCstore service.
359 *
360 * @param cls Handle to the PSYCstore service.
361 */
362static void
363reconnect (void *cls)
364{
365 struct GNUNET_PSYCSTORE_Handle *h = cls;
366
367 h->reconnect_task = NULL;
368 do_connect (cls);
369}
370
371
372/**
373 * Connect to the PSYCstore service.
374 *
375 * @param cfg The configuration to use
376 * @return Handle to use
377 */
378struct GNUNET_PSYCSTORE_Handle *
379GNUNET_PSYCSTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
380{
381 struct GNUNET_PSYCSTORE_Handle *h
382 = GNUNET_new (struct GNUNET_PSYCSTORE_Handle);
383 h->cfg = cfg;
384 h->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
385 do_connect (h);
386 return h;
387}
388
389
390/**
391 * Disconnect from PSYCstore service
392 *
393 * @param h Handle to destroy
394 */
395void
396GNUNET_PSYCSTORE_disconnect (struct GNUNET_PSYCSTORE_Handle *h)
397{
398 GNUNET_assert (NULL != h);
399 if (h->reconnect_task != NULL)
400 {
401 GNUNET_SCHEDULER_cancel (h->reconnect_task);
402 h->reconnect_task = NULL;
403 }
404 if (NULL != h->mq)
405 {
406 // FIXME: free data structures for pending operations
407 GNUNET_MQ_destroy (h->mq);
408 h->mq = NULL;
409 }
410 GNUNET_free (h);
411}
412
413
414/**
415 * Message sent notification.
416 *
417 * Remove invalidated envelope pointer.
418 */
419static void
420message_sent (void *cls)
421{
422 struct GNUNET_PSYCSTORE_OperationHandle *op = cls;
423 op->env = NULL;
424}
425
426
427/**
428 * Create a new operation.
429 */
430static struct GNUNET_PSYCSTORE_OperationHandle *
431op_create (struct GNUNET_PSYCSTORE_Handle *h,
432 struct GNUNET_OP_Handle *hop,
433 GNUNET_PSYCSTORE_ResultCallback result_cb,
434 void *cls)
435{
436 struct GNUNET_PSYCSTORE_OperationHandle *
437 op = GNUNET_malloc (sizeof (*op));
438 op->h = h;
439 op->op_id = GNUNET_OP_add (hop,
440 (GNUNET_ResultCallback) result_cb,
441 cls, op);
442 return op;
443}
444
445
446/**
447 * Send a message associated with an operation.
448 *
449 * @param h
450 * PSYCstore handle.
451 * @param op
452 * Operation handle.
453 * @param env
454 * Message envelope to send.
455 * @param[out] op_id
456 * Operation ID to write in network byte order. NULL if not needed.
457 *
458 * @return Operation handle.
459 *
460 */
461static struct GNUNET_PSYCSTORE_OperationHandle *
462op_send (struct GNUNET_PSYCSTORE_Handle *h,
463 struct GNUNET_PSYCSTORE_OperationHandle *op,
464 struct GNUNET_MQ_Envelope *env,
465 uint64_t *op_id)
466{
467 op->env = env;
468 if (NULL != op_id)
469 *op_id = GNUNET_htonll (op->op_id);
470
471 GNUNET_MQ_notify_sent (env, message_sent, op);
472 GNUNET_MQ_send (h->mq, env);
473 return op;
474}
475
476
477/**
478 * Cancel a PSYCstore operation. Note that the operation MAY still
479 * be executed; this merely cancels the continuation; if the request
480 * was already transmitted, the service may still choose to complete
481 * the operation.
482 *
483 * @param op Operation to cancel.
484 *
485 * @return #GNUNET_YES if message was not sent yet and got discarded,
486 * #GNUNET_NO if it was already sent, and only the callbacks got cancelled.
487 */
488int
489GNUNET_PSYCSTORE_operation_cancel (struct GNUNET_PSYCSTORE_OperationHandle *op)
490{
491 struct GNUNET_PSYCSTORE_Handle *h = op->h;
492 int ret = GNUNET_NO;
493
494 if (NULL != op->env)
495 {
496 GNUNET_MQ_send_cancel (op->env);
497 ret = GNUNET_YES;
498 }
499
500 GNUNET_OP_remove (h->op, op->op_id);
501 GNUNET_free (op);
502
503 return ret;
504}
505
506
507/**
508 * Store join/leave events for a PSYC channel in order to be able to answer
509 * membership test queries later.
510 *
511 * @param h
512 * Handle for the PSYCstore.
513 * @param channel_key
514 * The channel where the event happened.
515 * @param slave_key
516 * Public key of joining/leaving slave.
517 * @param did_join
518 * #GNUNET_YES on join, #GNUNET_NO on part.
519 * @param announced_at
520 * ID of the message that announced the membership change.
521 * @param effective_since
522 * Message ID this membership change is in effect since.
523 * For joins it is <= announced_at, for parts it is always 0.
524 * @param group_generation
525 * In case of a part, the last group generation the slave has access to.
526 * It has relevance when a larger message have fragments with different
527 * group generations.
528 * @param result_cb
529 * Callback to call with the result of the storage operation.
530 * @param cls
531 * Closure for the callback.
532 *
533 * @return Operation handle that can be used to cancel the operation.
534 */
535struct GNUNET_PSYCSTORE_OperationHandle *
536GNUNET_PSYCSTORE_membership_store (struct GNUNET_PSYCSTORE_Handle *h,
537 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
538 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
539 int did_join,
540 uint64_t announced_at,
541 uint64_t effective_since,
542 uint64_t group_generation,
543 GNUNET_PSYCSTORE_ResultCallback result_cb,
544 void *cls)
545{
546 GNUNET_assert (NULL != h);
547 GNUNET_assert (NULL != channel_key);
548 GNUNET_assert (NULL != slave_key);
549 GNUNET_assert (GNUNET_YES == did_join || GNUNET_NO == did_join);
550 GNUNET_assert (did_join
551 ? effective_since <= announced_at
552 : effective_since == 0);
553
554 struct MembershipStoreRequest *req;
555 struct GNUNET_MQ_Envelope *
556 env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_STORE);
557 req->channel_key = *channel_key;
558 req->slave_key = *slave_key;
559 req->did_join = did_join;
560 req->announced_at = GNUNET_htonll (announced_at);
561 req->effective_since = GNUNET_htonll (effective_since);
562 req->group_generation = GNUNET_htonll (group_generation);
563
564 return
565 op_send (h, op_create (h, h->op, result_cb, cls),
566 env, &req->op_id);
567}
568
569
570/**
571 * Test if a member was admitted to the channel at the given message ID.
572 *
573 * This is useful when relaying and replaying messages to check if a particular
574 * slave has access to the message fragment with a given group generation. It
575 * is also used when handling join requests to determine whether the slave is
576 * currently admitted to the channel.
577 *
578 * @param h
579 * Handle for the PSYCstore.
580 * @param channel_key
581 * The channel we are interested in.
582 * @param slave_key
583 * Public key of slave whose membership to check.
584 * @param message_id
585 * Message ID for which to do the membership test.
586 * @param group_generation
587 * Group generation of the fragment of the message to test.
588 * It has relevance if the message consists of multiple fragments with
589 * different group generations.
590 * @param result_cb
591 * Callback to call with the test result.
592 * @param cls
593 * Closure for the callback.
594 *
595 * @return Operation handle that can be used to cancel the operation.
596 */
597struct GNUNET_PSYCSTORE_OperationHandle *
598GNUNET_PSYCSTORE_membership_test (struct GNUNET_PSYCSTORE_Handle *h,
599 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
600 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
601 uint64_t message_id,
602 uint64_t group_generation,
603 GNUNET_PSYCSTORE_ResultCallback result_cb,
604 void *cls)
605{
606 struct MembershipTestRequest *req;
607 struct GNUNET_MQ_Envelope *
608 env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_TEST);
609 req->channel_key = *channel_key;
610 req->slave_key = *slave_key;
611 req->message_id = GNUNET_htonll (message_id);
612 req->group_generation = GNUNET_htonll (group_generation);
613
614 return
615 op_send (h, op_create (h, h->op, result_cb, cls),
616 env, &req->op_id);
617}
618
619
620/**
621 * Store a message fragment sent to a channel.
622 *
623 * @param h Handle for the PSYCstore.
624 * @param channel_key The channel the message belongs to.
625 * @param message Message to store.
626 * @param psycstore_flags Flags indicating whether the PSYC message contains
627 * state modifiers.
628 * @param result_cb Callback to call with the result of the operation.
629 * @param cls Closure for the callback.
630 *
631 * @return Handle that can be used to cancel the operation.
632 */
633struct GNUNET_PSYCSTORE_OperationHandle *
634GNUNET_PSYCSTORE_fragment_store (struct GNUNET_PSYCSTORE_Handle *h,
635 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
636 const struct GNUNET_MULTICAST_MessageHeader *msg,
637 enum GNUNET_PSYCSTORE_MessageFlags psycstore_flags,
638 GNUNET_PSYCSTORE_ResultCallback result_cb,
639 void *cls)
640{
641 uint16_t size = ntohs (msg->header.size);
642 struct FragmentStoreRequest *req;
643 struct GNUNET_MQ_Envelope *
644 env = GNUNET_MQ_msg_extra (req, size,
645 GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_STORE);
646 req->channel_key = *channel_key;
647 req->psycstore_flags = htonl (psycstore_flags);
648 GNUNET_memcpy (&req[1], msg, size);
649
650 return
651 op_send (h, op_create (h, h->op, result_cb, cls),
652 env, &req->op_id);
653}
654
655
656/**
657 * Retrieve message fragments by fragment ID range.
658 *
659 * @param h
660 * Handle for the PSYCstore.
661 * @param channel_key
662 * The channel we are interested in.
663 * @param slave_key
664 * The slave requesting the fragment. If not NULL, a membership test is
665 * performed first and the fragment is only returned if the slave has
666 * access to it.
667 * @param first_fragment_id
668 * First fragment ID to retrieve.
669 * Use 0 to get the latest message fragment.
670 * @param last_fragment_id
671 * Last consecutive fragment ID to retrieve.
672 * Use 0 to get the latest message fragment.
673 * @param fragment_limit
674 * Maximum number of fragments to retrieve.
675 * @param fragment_cb
676 * Callback to call with the retrieved fragments.
677 * @param result_cb
678 * Callback to call with the result of the operation.
679 * @param cls
680 * Closure for the callbacks.
681 *
682 * @return Handle that can be used to cancel the operation.
683 */
684struct GNUNET_PSYCSTORE_OperationHandle *
685GNUNET_PSYCSTORE_fragment_get (struct GNUNET_PSYCSTORE_Handle *h,
686 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
687 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
688 uint64_t first_fragment_id,
689 uint64_t last_fragment_id,
690 GNUNET_PSYCSTORE_FragmentCallback fragment_cb,
691 GNUNET_PSYCSTORE_ResultCallback result_cb,
692 void *cls)
693{
694 struct FragmentGetRequest *req;
695 struct GNUNET_MQ_Envelope *
696 env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_GET);
697 req->channel_key = *channel_key;
698 req->first_fragment_id = GNUNET_htonll (first_fragment_id);
699 req->last_fragment_id = GNUNET_htonll (last_fragment_id);
700 if (NULL != slave_key)
701 {
702 req->slave_key = *slave_key;
703 req->do_membership_test = GNUNET_YES;
704 }
705
706 struct GNUNET_PSYCSTORE_OperationHandle *
707 op = op_create (h, h->op, result_cb, cls);
708 op->fragment_cb = fragment_cb;
709 op->cls = cls;
710 return op_send (h, op, env, &req->op_id);
711}
712
713
714/**
715 * Retrieve latest message fragments.
716 *
717 * @param h
718 * Handle for the PSYCstore.
719 * @param channel_key
720 * The channel we are interested in.
721 * @param slave_key
722 * The slave requesting the fragment. If not NULL, a membership test is
723 * performed first and the fragment is only returned if the slave has
724 * access to it.
725 * @param first_fragment_id
726 * First fragment ID to retrieve.
727 * Use 0 to get the latest message fragment.
728 * @param last_fragment_id
729 * Last consecutive fragment ID to retrieve.
730 * Use 0 to get the latest message fragment.
731 * @param fragment_limit
732 * Maximum number of fragments to retrieve.
733 * @param fragment_cb
734 * Callback to call with the retrieved fragments.
735 * @param result_cb
736 * Callback to call with the result of the operation.
737 * @param cls
738 * Closure for the callbacks.
739 *
740 * @return Handle that can be used to cancel the operation.
741 */
742struct GNUNET_PSYCSTORE_OperationHandle *
743GNUNET_PSYCSTORE_fragment_get_latest (struct GNUNET_PSYCSTORE_Handle *h,
744 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
745 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
746 uint64_t fragment_limit,
747 GNUNET_PSYCSTORE_FragmentCallback fragment_cb,
748 GNUNET_PSYCSTORE_ResultCallback result_cb,
749 void *cls)
750{
751 struct FragmentGetRequest *req;
752 struct GNUNET_MQ_Envelope *
753 env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_GET);
754 req->channel_key = *channel_key;
755 req->fragment_limit = GNUNET_ntohll (fragment_limit);
756 if (NULL != slave_key)
757 {
758 req->slave_key = *slave_key;
759 req->do_membership_test = GNUNET_YES;
760 }
761
762 struct GNUNET_PSYCSTORE_OperationHandle *
763 op = op_create (h, h->op, result_cb, cls);
764 op->fragment_cb = fragment_cb;
765 op->cls = cls;
766 return op_send (h, op, env, &req->op_id);
767}
768
769
770/**
771 * Retrieve all fragments of messages in a message ID range.
772 *
773 * @param h
774 * Handle for the PSYCstore.
775 * @param channel_key
776 * The channel we are interested in.
777 * @param slave_key
778 * The slave requesting the message.
779 * If not NULL, a membership test is performed first
780 * and the message is only returned if the slave has access to it.
781 * @param first_message_id
782 * First message ID to retrieve.
783 * @param last_message_id
784 * Last consecutive message ID to retrieve.
785 * @param fragment_limit
786 * Maximum number of fragments to retrieve.
787 * @param method_prefix
788 * Retrieve only messages with a matching method prefix.
789 * @todo Implement method_prefix query.
790 * @param fragment_cb
791 * Callback to call with the retrieved fragments.
792 * @param result_cb
793 * Callback to call with the result of the operation.
794 * @param cls
795 * Closure for the callbacks.
796 *
797 * @return Handle that can be used to cancel the operation.
798 */
799struct GNUNET_PSYCSTORE_OperationHandle *
800GNUNET_PSYCSTORE_message_get (struct GNUNET_PSYCSTORE_Handle *h,
801 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
802 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
803 uint64_t first_message_id,
804 uint64_t last_message_id,
805 uint64_t fragment_limit,
806 const char *method_prefix,
807 GNUNET_PSYCSTORE_FragmentCallback fragment_cb,
808 GNUNET_PSYCSTORE_ResultCallback result_cb,
809 void *cls)
810{
811 struct MessageGetRequest *req;
812 if (NULL == method_prefix)
813 method_prefix = "";
814 uint16_t method_size = strnlen (method_prefix,
815 GNUNET_MAX_MESSAGE_SIZE
816 - sizeof (*req)) + 1;
817
818 struct GNUNET_MQ_Envelope *
819 env = GNUNET_MQ_msg_extra (req, method_size,
820 GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET);
821 req->channel_key = *channel_key;
822 req->first_message_id = GNUNET_htonll (first_message_id);
823 req->last_message_id = GNUNET_htonll (last_message_id);
824 req->fragment_limit = GNUNET_htonll (fragment_limit);
825 if (NULL != slave_key)
826 {
827 req->slave_key = *slave_key;
828 req->do_membership_test = GNUNET_YES;
829 }
830 GNUNET_memcpy (&req[1], method_prefix, method_size);
831 ((char *) &req[1])[method_size - 1] = '\0';
832
833 struct GNUNET_PSYCSTORE_OperationHandle *
834 op = op_create (h, h->op, result_cb, cls);
835 op->fragment_cb = fragment_cb;
836 op->cls = cls;
837 return op_send (h, op, env, &req->op_id);
838}
839
840
841/**
842 * Retrieve all fragments of the latest messages.
843 *
844 * @param h
845 * Handle for the PSYCstore.
846 * @param channel_key
847 * The channel we are interested in.
848 * @param slave_key
849 * The slave requesting the message.
850 * If not NULL, a membership test is performed first
851 * and the message is only returned if the slave has access to it.
852 * @param message_limit
853 * Maximum number of messages to retrieve.
854 * @param method_prefix
855 * Retrieve only messages with a matching method prefix.
856 * @todo Implement method_prefix query.
857 * @param fragment_cb
858 * Callback to call with the retrieved fragments.
859 * @param result_cb
860 * Callback to call with the result of the operation.
861 * @param cls
862 * Closure for the callbacks.
863 *
864 * @return Handle that can be used to cancel the operation.
865 */
866struct GNUNET_PSYCSTORE_OperationHandle *
867GNUNET_PSYCSTORE_message_get_latest (struct GNUNET_PSYCSTORE_Handle *h,
868 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
869 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
870 uint64_t message_limit,
871 const char *method_prefix,
872 GNUNET_PSYCSTORE_FragmentCallback fragment_cb,
873 GNUNET_PSYCSTORE_ResultCallback result_cb,
874 void *cls)
875{
876 struct MessageGetRequest *req;
877
878 if (NULL == method_prefix)
879 method_prefix = "";
880 uint16_t method_size = strnlen (method_prefix,
881 GNUNET_MAX_MESSAGE_SIZE
882 - sizeof (*req)) + 1;
883 GNUNET_assert ('\0' == method_prefix[method_size - 1]);
884
885 struct GNUNET_MQ_Envelope *
886 env = GNUNET_MQ_msg_extra (req, method_size,
887 GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET);
888 req->channel_key = *channel_key;
889 req->message_limit = GNUNET_ntohll (message_limit);
890 if (NULL != slave_key)
891 {
892 req->slave_key = *slave_key;
893 req->do_membership_test = GNUNET_YES;
894 }
895 GNUNET_memcpy (&req[1], method_prefix, method_size);
896
897 struct GNUNET_PSYCSTORE_OperationHandle *
898 op = op_create (h, h->op, result_cb, cls);
899 op->fragment_cb = fragment_cb;
900 op->cls = cls;
901 return op_send (h, op, env, &req->op_id);
902}
903
904
905/**
906 * Retrieve a fragment of message specified by its message ID and fragment
907 * offset.
908 *
909 * @param h
910 * Handle for the PSYCstore.
911 * @param channel_key
912 * The channel we are interested in.
913 * @param slave_key
914 * The slave requesting the message fragment. If not NULL, a membership
915 * test is performed first and the message fragment is only returned
916 * if the slave has access to it.
917 * @param message_id
918 * Message ID to retrieve. Use 0 to get the latest message.
919 * @param fragment_offset
920 * Offset of the fragment to retrieve.
921 * @param fragment_cb
922 * Callback to call with the retrieved fragments.
923 * @param result_cb
924 * Callback to call with the result of the operation.
925 * @param cls
926 * Closure for the callbacks.
927 *
928 * @return Handle that can be used to cancel the operation.
929 */
930struct GNUNET_PSYCSTORE_OperationHandle *
931GNUNET_PSYCSTORE_message_get_fragment (struct GNUNET_PSYCSTORE_Handle *h,
932 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
933 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
934 uint64_t message_id,
935 uint64_t fragment_offset,
936 GNUNET_PSYCSTORE_FragmentCallback fragment_cb,
937 GNUNET_PSYCSTORE_ResultCallback result_cb,
938 void *cls)
939{
940 struct MessageGetFragmentRequest *req;
941 struct GNUNET_MQ_Envelope *
942 env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET_FRAGMENT);
943
944 req->channel_key = *channel_key;
945 req->message_id = GNUNET_htonll (message_id);
946 req->fragment_offset = GNUNET_htonll (fragment_offset);
947 if (NULL != slave_key)
948 {
949 req->slave_key = *slave_key;
950 req->do_membership_test = GNUNET_YES;
951 }
952
953 struct GNUNET_PSYCSTORE_OperationHandle *
954 op = op_create (h, h->op, result_cb, cls);
955 op->fragment_cb = fragment_cb;
956 op->cls = cls;
957 return op_send (h, op, env, &req->op_id);
958}
959
960
961/**
962 * Retrieve latest values of counters for a channel master.
963 *
964 * The current value of counters are needed when a channel master is restarted,
965 * so that it can continue incrementing the counters from their last value.
966 *
967 * @param h
968 * Handle for the PSYCstore.
969 * @param channel_key
970 * Public key that identifies the channel.
971 * @param ccb
972 * Callback to call with the result.
973 * @param ccb_cls
974 * Closure for the @a ccb callback.
975 *
976 * @return Handle that can be used to cancel the operation.
977 */
978struct GNUNET_PSYCSTORE_OperationHandle *
979GNUNET_PSYCSTORE_counters_get (struct GNUNET_PSYCSTORE_Handle *h,
980 struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
981 GNUNET_PSYCSTORE_CountersCallback counters_cb,
982 void *cls)
983{
984 struct OperationRequest *req;
985 struct GNUNET_MQ_Envelope *
986 env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_COUNTERS_GET);
987 req->channel_key = *channel_key;
988
989 struct GNUNET_PSYCSTORE_OperationHandle *
990 op = op_create (h, h->op, NULL, NULL);
991 op->counters_cb = counters_cb;
992 op->cls = cls;
993 return op_send (h, op, env, &req->op_id);
994}
995
996
997/**
998 * Apply modifiers of a message to the current channel state.
999 *
1000 * An error is returned if there are missing messages containing state
1001 * operations before the current one.
1002 *
1003 * @param h
1004 * Handle for the PSYCstore.
1005 * @param channel_key
1006 * The channel we are interested in.
1007 * @param message_id
1008 * ID of the message that contains the @a modifiers.
1009 * @param state_delta
1010 * Value of the _state_delta PSYC header variable of the message.
1011 * @param result_cb
1012 * Callback to call with the result of the operation.
1013 * @param cls
1014 * Closure for @a result_cb.
1015 *
1016 * @return Handle that can be used to cancel the operation.
1017 */
1018struct GNUNET_PSYCSTORE_OperationHandle *
1019GNUNET_PSYCSTORE_state_modify (struct GNUNET_PSYCSTORE_Handle *h,
1020 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1021 uint64_t message_id,
1022 uint64_t state_delta,
1023 GNUNET_PSYCSTORE_ResultCallback result_cb,
1024 void *cls)
1025{
1026 struct StateModifyRequest *req;
1027 struct GNUNET_MQ_Envelope *
1028 env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_MODIFY);
1029 req->channel_key = *channel_key;
1030 req->message_id = GNUNET_htonll (message_id);
1031 req->state_delta = GNUNET_htonll (state_delta);
1032
1033 return op_send (h, op_create (h, h->op, result_cb, cls),
1034 env, &req->op_id);
1035}
1036
1037
1038struct StateSyncClosure
1039{
1040 GNUNET_PSYCSTORE_ResultCallback result_cb;
1041 void *cls;
1042 uint8_t last;
1043};
1044
1045
1046static void
1047state_sync_result (void *cls, int64_t result,
1048 const char *err_msg, uint16_t err_msg_size)
1049{
1050 struct StateSyncClosure *ssc = cls;
1051 if (GNUNET_OK != result || ssc->last)
1052 ssc->result_cb (ssc->cls, result, err_msg, err_msg_size);
1053 GNUNET_free (ssc);
1054}
1055
1056
1057/**
1058 * Store synchronized state.
1059 *
1060 * @param h
1061 * Handle for the PSYCstore.
1062 * @param channel_key
1063 * The channel we are interested in.
1064 * @param max_state_message_id
1065 * ID of the last stateful message before @a state_hash_message_id.
1066 * @param state_hash_message_id
1067 * ID of the message that contains the state_hash PSYC header variable.
1068 * @param modifier_count
1069 * Number of elements in the @a modifiers array.
1070 * @param modifiers
1071 * Full state to store.
1072 * @param result_cb
1073 * Callback to call with the result of the operation.
1074 * @param cls
1075 * Closure for the callback.
1076 *
1077 * @return Handle that can be used to cancel the operation.
1078 */
1079struct GNUNET_PSYCSTORE_OperationHandle *
1080GNUNET_PSYCSTORE_state_sync (struct GNUNET_PSYCSTORE_Handle *h,
1081 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1082 uint64_t max_state_message_id,
1083 uint64_t state_hash_message_id,
1084 size_t modifier_count,
1085 const struct GNUNET_PSYC_Modifier *modifiers,
1086 GNUNET_PSYCSTORE_ResultCallback result_cb,
1087 void *cls)
1088{
1089 struct GNUNET_PSYCSTORE_OperationHandle *op = NULL;
1090 size_t i;
1091
1092 for (i = 0; i < modifier_count; i++) {
1093 struct StateSyncRequest *req;
1094 uint16_t name_size = strlen (modifiers[i].name) + 1;
1095
1096 struct GNUNET_MQ_Envelope *
1097 env = GNUNET_MQ_msg_extra (req,
1098 sizeof (*req) + name_size + modifiers[i].value_size,
1099 GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_SYNC);
1100
1101 req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_SYNC);
1102 req->header.size = htons (sizeof (*req) + name_size
1103 + modifiers[i].value_size);
1104 req->channel_key = *channel_key;
1105 req->max_state_message_id = GNUNET_htonll (max_state_message_id);
1106 req->state_hash_message_id = GNUNET_htonll (state_hash_message_id);
1107 req->name_size = htons (name_size);
1108 req->flags
1109 = (0 == i)
1110 ? STATE_OP_FIRST
1111 : (modifier_count - 1 == i)
1112 ? STATE_OP_LAST
1113 : 0;
1114
1115 GNUNET_memcpy (&req[1], modifiers[i].name, name_size);
1116 GNUNET_memcpy ((char *) &req[1] + name_size, modifiers[i].value, modifiers[i].value_size);
1117
1118 struct StateSyncClosure *ssc = GNUNET_malloc (sizeof (*ssc));
1119 ssc->last = (req->flags & STATE_OP_LAST);
1120 ssc->result_cb = result_cb;
1121 ssc->cls = cls;
1122
1123 op_send (h, op_create (h, h->op, state_sync_result, ssc),
1124 env, &req->op_id);
1125 }
1126 // FIXME: only one operation is returned,
1127 // add pointers to other operations and make all cancellable.
1128 return op;
1129}
1130
1131
1132/**
1133 * Reset the state of a channel.
1134 *
1135 * Delete all state variables stored for the given channel.
1136 *
1137 * @param h
1138 * Handle for the PSYCstore.
1139 * @param channel_key
1140 * The channel we are interested in.
1141 * @param result_cb
1142 * Callback to call with the result of the operation.
1143 * @param cls
1144 * Closure for the callback.
1145 *
1146 * @return Handle that can be used to cancel the operation.
1147 */
1148struct GNUNET_PSYCSTORE_OperationHandle *
1149GNUNET_PSYCSTORE_state_reset (struct GNUNET_PSYCSTORE_Handle *h,
1150 const struct GNUNET_CRYPTO_EddsaPublicKey
1151 *channel_key,
1152 GNUNET_PSYCSTORE_ResultCallback result_cb,
1153 void *cls)
1154{
1155 struct OperationRequest *req;
1156 struct GNUNET_MQ_Envelope *
1157 env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_RESET);
1158 req->channel_key = *channel_key;
1159
1160 return
1161 op_send (h, op_create (h, h->op, result_cb, cls),
1162 env, &req->op_id);
1163}
1164
1165
1166/**
1167 * Update signed values of state variables in the state store.
1168 *
1169 * @param h
1170 * Handle for the PSYCstore.
1171 * @param channel_key
1172 * The channel we are interested in.
1173 * @param message_id
1174 * Message ID that contained the state @a hash.
1175 * @param hash
1176 * Hash of the serialized full state.
1177 * @param result_cb
1178 * Callback to call with the result of the operation.
1179 * @param cls
1180 * Closure for the callback.
1181 */
1182struct GNUNET_PSYCSTORE_OperationHandle *
1183GNUNET_PSYCSTORE_state_hash_update (struct GNUNET_PSYCSTORE_Handle *h,
1184 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1185 uint64_t message_id,
1186 const struct GNUNET_HashCode *hash,
1187 GNUNET_PSYCSTORE_ResultCallback result_cb,
1188 void *cls)
1189{
1190 struct StateHashUpdateRequest *req;
1191 struct GNUNET_MQ_Envelope *
1192 env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_HASH_UPDATE);
1193 req->channel_key = *channel_key;
1194 req->hash = *hash;
1195
1196 return
1197 op_send (h, op_create (h, h->op, result_cb, cls),
1198 env, &req->op_id);
1199}
1200
1201
1202/**
1203 * Retrieve the best matching state variable.
1204 *
1205 * @param h
1206 * Handle for the PSYCstore.
1207 * @param channel_key
1208 * The channel we are interested in.
1209 * @param name
1210 * Name of variable to match, the returned variable might be less specific.
1211 * @param state_cb
1212 * Callback to return the matching state variable.
1213 * @param result_cb
1214 * Callback to call with the result of the operation.
1215 * @param cls
1216 * Closure for the callbacks.
1217 *
1218 * @return Handle that can be used to cancel the operation.
1219 */
1220struct GNUNET_PSYCSTORE_OperationHandle *
1221GNUNET_PSYCSTORE_state_get (struct GNUNET_PSYCSTORE_Handle *h,
1222 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1223 const char *name,
1224 GNUNET_PSYCSTORE_StateCallback state_cb,
1225 GNUNET_PSYCSTORE_ResultCallback result_cb,
1226 void *cls)
1227{
1228 size_t name_size = strlen (name) + 1;
1229 struct OperationRequest *req;
1230 struct GNUNET_MQ_Envelope *
1231 env = GNUNET_MQ_msg_extra (req, name_size,
1232 GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_GET);
1233 req->channel_key = *channel_key;
1234 GNUNET_memcpy (&req[1], name, name_size);
1235
1236 struct GNUNET_PSYCSTORE_OperationHandle *
1237 op = op_create (h, h->op, result_cb, cls);
1238 op->state_cb = state_cb;
1239 op->cls = cls;
1240 return op_send (h, op, env, &req->op_id);
1241}
1242
1243
1244/**
1245 * Retrieve all state variables for a channel with the given prefix.
1246 *
1247 * @param h
1248 * Handle for the PSYCstore.
1249 * @param channel_key
1250 * The channel we are interested in.
1251 * @param name_prefix
1252 * Prefix of state variable names to match.
1253 * @param state_cb
1254 * Callback to return matching state variables.
1255 * @param result_cb
1256 * Callback to call with the result of the operation.
1257 * @param cls
1258 * Closure for the callbacks.
1259 *
1260 * @return Handle that can be used to cancel the operation.
1261 */
1262struct GNUNET_PSYCSTORE_OperationHandle *
1263GNUNET_PSYCSTORE_state_get_prefix (struct GNUNET_PSYCSTORE_Handle *h,
1264 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1265 const char *name_prefix,
1266 GNUNET_PSYCSTORE_StateCallback state_cb,
1267 GNUNET_PSYCSTORE_ResultCallback result_cb,
1268 void *cls)
1269{
1270 size_t name_size = strlen (name_prefix) + 1;
1271 struct OperationRequest *req;
1272 struct GNUNET_MQ_Envelope *
1273 env = GNUNET_MQ_msg_extra (req, name_size,
1274 GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_GET_PREFIX);
1275 req->channel_key = *channel_key;
1276 GNUNET_memcpy (&req[1], name_prefix, name_size);
1277
1278 struct GNUNET_PSYCSTORE_OperationHandle *
1279 op = op_create (h, h->op, result_cb, cls);
1280 op->state_cb = state_cb;
1281 op->cls = cls;
1282 return op_send (h, op, env, &req->op_id);
1283}
1284
1285/* 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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @author Gabor X Toth
23 * @author Christian Grothoff
24 *
25 * @file
26 * Test for the PSYCstore plugins.
27 */
28
29#include <inttypes.h>
30
31#include "platform.h"
32#include "gnunet_util_lib.h"
33#include "gnunet_testing_lib.h"
34#include "gnunet_psycstore_plugin.h"
35#include "gnunet_psycstore_service.h"
36#include "gnunet_multicast_service.h"
37
38#define DEBUG_PSYCSTORE GNUNET_EXTRA_LOGGING
39#if DEBUG_PSYCSTORE
40# define LOG_LEVEL "DEBUG"
41#else
42# define LOG_LEVEL "WARNING"
43#endif
44
45#define C2ARG(str) str, (sizeof (str) - 1)
46
47#define LOG(kind,...) \
48 GNUNET_log_from (kind, "test-plugin-psycstore", __VA_ARGS__)
49
50static int ok;
51
52/**
53 * Name of plugin under test.
54 */
55static const char *plugin_name;
56
57static struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key;
58static struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key;
59
60static struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key;
61static struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key;
62
63/**
64 * Function called when the service shuts down. Unloads our psycstore
65 * plugin.
66 *
67 * @param api api to unload
68 */
69static void
70unload_plugin (struct GNUNET_PSYCSTORE_PluginFunctions *api)
71{
72 char *libname;
73
74 GNUNET_asprintf (&libname, "libgnunet_plugin_psycstore_%s", plugin_name);
75 GNUNET_break (NULL == GNUNET_PLUGIN_unload (libname, api));
76 GNUNET_free (libname);
77}
78
79
80/**
81 * Load the psycstore plugin.
82 *
83 * @param cfg configuration to pass
84 * @return NULL on error
85 */
86static struct GNUNET_PSYCSTORE_PluginFunctions *
87load_plugin (const struct GNUNET_CONFIGURATION_Handle *cfg)
88{
89 struct GNUNET_PSYCSTORE_PluginFunctions *ret;
90 char *libname;
91
92 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Loading `%s' psycstore plugin\n"),
93 plugin_name);
94 GNUNET_asprintf (&libname, "libgnunet_plugin_psycstore_%s", plugin_name);
95 if (NULL == (ret = GNUNET_PLUGIN_load (libname, (void*) cfg)))
96 {
97 FPRINTF (stderr, "Failed to load plugin `%s'!\n", plugin_name);
98 return NULL;
99 }
100 GNUNET_free (libname);
101 return ret;
102}
103
104
105#define MAX_MSG 16
106
107struct FragmentClosure
108{
109 uint8_t n;
110 uint64_t flags[MAX_MSG];
111 struct GNUNET_MULTICAST_MessageHeader *msg[MAX_MSG];
112};
113
114static int
115fragment_cb (void *cls, struct GNUNET_MULTICAST_MessageHeader *msg2,
116 enum GNUNET_PSYCSTORE_MessageFlags flags)
117{
118 struct FragmentClosure *fcls = cls;
119 struct GNUNET_MULTICAST_MessageHeader *msg1;
120 uint64_t flags1;
121 int ret;
122
123 if (fcls->n >= MAX_MSG)
124 {
125 GNUNET_break (0);
126 return GNUNET_SYSERR;
127 }
128 msg1 = fcls->msg[fcls->n];
129 flags1 = fcls->flags[fcls->n++];
130 if (NULL == msg1)
131 {
132 GNUNET_break (0);
133 return GNUNET_SYSERR;
134 }
135
136 if (flags1 == flags && msg1->header.size == msg2->header.size
137 && 0 == memcmp (msg1, msg2, ntohs (msg1->header.size)))
138 {
139 LOG (GNUNET_ERROR_TYPE_DEBUG, "Fragment %llu matches\n",
140 GNUNET_ntohll (msg1->fragment_id));
141 ret = GNUNET_YES;
142 }
143 else
144 {
145 LOG (GNUNET_ERROR_TYPE_ERROR, "Fragment %llu differs\n",
146 GNUNET_ntohll (msg1->fragment_id));
147 ret = GNUNET_SYSERR;
148 }
149
150 GNUNET_free (msg2);
151 return ret;
152}
153
154
155struct StateClosure {
156 size_t n;
157 char *name[16];
158 void *value[16];
159 size_t value_size[16];
160};
161
162static int
163state_cb (void *cls, const char *name, const void *value, uint32_t value_size)
164{
165 struct StateClosure *scls = cls;
166 const void *val = scls->value[scls->n]; // FIXME: check for n out-of-bounds FIRST!
167 size_t val_size = scls->value_size[scls->n++];
168
169 /* FIXME: check name */
170
171 LOG (GNUNET_ERROR_TYPE_DEBUG,
172 " name = %s, value_size = %u\n",
173 name, value_size);
174
175 return GNUNET_YES;
176 return value_size == val_size && 0 == memcmp (value, val, val_size)
177 ? GNUNET_YES
178 : GNUNET_SYSERR;
179}
180
181
182static void
183run (void *cls, char *const *args, const char *cfgfile,
184 const struct GNUNET_CONFIGURATION_Handle *cfg)
185{
186 struct GNUNET_PSYCSTORE_PluginFunctions *db;
187
188 ok = 1;
189 db = load_plugin (cfg);
190 if (NULL == db)
191 {
192 FPRINTF (stderr,
193 "%s",
194 "Failed to initialize PSYCstore. "
195 "Database likely not setup, skipping test.\n");
196 ok = 77;
197 return;
198 }
199
200 /* Store & test membership */
201
202 LOG (GNUNET_ERROR_TYPE_INFO, "MEMBERSHIP\n");
203
204 channel_key = GNUNET_CRYPTO_eddsa_key_create ();
205 slave_key = GNUNET_CRYPTO_ecdsa_key_create ();
206
207 GNUNET_CRYPTO_eddsa_key_get_public (channel_key,
208 &channel_pub_key);
209 GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key);
210
211 LOG (GNUNET_ERROR_TYPE_INFO, "membership_store()\n");
212
213 GNUNET_assert (GNUNET_OK == db->membership_store (db->cls, &channel_pub_key,
214 &slave_pub_key, GNUNET_YES,
215 4, 2, 1));
216
217 LOG (GNUNET_ERROR_TYPE_INFO, "membership_test()\n");
218
219 GNUNET_assert (GNUNET_YES == db->membership_test (db->cls, &channel_pub_key,
220 &slave_pub_key, 4));
221
222 GNUNET_assert (GNUNET_YES == db->membership_test (db->cls, &channel_pub_key,
223 &slave_pub_key, 2));
224
225 GNUNET_assert (GNUNET_NO == db->membership_test (db->cls, &channel_pub_key,
226 &slave_pub_key, 1));
227
228 /* Store & get messages */
229
230 LOG (GNUNET_ERROR_TYPE_INFO, "MESSAGES\n");
231
232 struct GNUNET_MULTICAST_MessageHeader *msg
233 = GNUNET_malloc (sizeof (*msg) + sizeof (channel_pub_key));
234 GNUNET_assert (msg != NULL);
235
236 msg->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE);
237 msg->header.size = htons (sizeof (*msg) + sizeof (channel_pub_key));
238
239 uint64_t fragment_id = INT64_MAX - 1;
240 msg->fragment_id = GNUNET_htonll (fragment_id);
241
242 uint64_t message_id = INT64_MAX - 10;
243 msg->message_id = GNUNET_htonll (message_id);
244
245 uint64_t group_generation = INT64_MAX - 3;
246 msg->group_generation = GNUNET_htonll (group_generation);
247
248 msg->hop_counter = htonl (9);
249 msg->fragment_offset = GNUNET_htonll (0);
250 msg->flags = htonl (GNUNET_MULTICAST_MESSAGE_LAST_FRAGMENT);
251
252 GNUNET_memcpy (&msg[1], &channel_pub_key, sizeof (channel_pub_key));
253
254 msg->purpose.size = htonl (ntohs (msg->header.size)
255 - sizeof (msg->header)
256 - sizeof (msg->hop_counter)
257 - sizeof (msg->signature));
258 msg->purpose.purpose = htonl (234);
259 GNUNET_assert (GNUNET_OK ==
260 GNUNET_CRYPTO_eddsa_sign (channel_key, &msg->purpose, &msg->signature));
261
262 LOG (GNUNET_ERROR_TYPE_INFO, "fragment_store()\n");
263
264 struct FragmentClosure fcls = { 0 };
265 fcls.n = 0;
266 fcls.msg[0] = msg;
267 fcls.flags[0] = GNUNET_PSYCSTORE_MESSAGE_STATE;
268
269 GNUNET_assert (
270 GNUNET_OK == db->fragment_store (db->cls, &channel_pub_key, msg,
271 fcls.flags[0]));
272
273 LOG (GNUNET_ERROR_TYPE_INFO, "fragment_get(%" PRIu64 ")\n", fragment_id);
274
275 uint64_t ret_frags = 0;
276 GNUNET_assert (
277 GNUNET_OK == db->fragment_get (db->cls, &channel_pub_key,
278 fragment_id, fragment_id,
279 &ret_frags, fragment_cb, &fcls));
280 GNUNET_assert (fcls.n == 1);
281
282 LOG (GNUNET_ERROR_TYPE_INFO, "message_get_fragment()\n");
283
284 fcls.n = 0;
285 GNUNET_assert (
286 GNUNET_OK == db->message_get_fragment (db->cls, &channel_pub_key,
287 GNUNET_ntohll (msg->message_id),
288 GNUNET_ntohll (msg->fragment_offset),
289 fragment_cb, &fcls));
290 GNUNET_assert (fcls.n == 1);
291
292 LOG (GNUNET_ERROR_TYPE_INFO, "message_add_flags()\n");
293 GNUNET_assert (
294 GNUNET_OK == db->message_add_flags (db->cls, &channel_pub_key,
295 GNUNET_ntohll (msg->message_id),
296 GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED));
297 LOG (GNUNET_ERROR_TYPE_INFO, "fragment_get(%" PRIu64 ")\n", fragment_id);
298
299 fcls.n = 0;
300 fcls.flags[0] |= GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED;
301
302 GNUNET_assert (
303 GNUNET_OK == db->fragment_get (db->cls, &channel_pub_key,
304 fragment_id, fragment_id,
305 &ret_frags, fragment_cb, &fcls));
306
307 GNUNET_assert (fcls.n == 1);
308
309 LOG (GNUNET_ERROR_TYPE_INFO, "fragment_store()\n");
310
311 struct GNUNET_MULTICAST_MessageHeader *msg1
312 = GNUNET_malloc (sizeof (*msg1) + sizeof (channel_pub_key));
313
314 GNUNET_memcpy (msg1, msg, sizeof (*msg1) + sizeof (channel_pub_key));
315
316 msg1->fragment_id = GNUNET_htonll (INT64_MAX);
317 msg1->fragment_offset = GNUNET_htonll (32768);
318
319 fcls.n = 0;
320 fcls.msg[1] = msg1;
321 fcls.flags[1] = GNUNET_PSYCSTORE_MESSAGE_STATE_HASH;
322
323 GNUNET_assert (GNUNET_OK == db->fragment_store (db->cls, &channel_pub_key, msg1,
324 fcls.flags[1]));
325
326 LOG (GNUNET_ERROR_TYPE_INFO, "message_get()\n");
327
328 GNUNET_assert (
329 GNUNET_OK == db->message_get (db->cls, &channel_pub_key,
330 message_id, message_id, 0,
331 &ret_frags, fragment_cb, &fcls));
332 GNUNET_assert (fcls.n == 2 && ret_frags == 2);
333
334 /* Message counters */
335
336 LOG (GNUNET_ERROR_TYPE_INFO, "counters_message_get()\n");
337
338 fragment_id = 0;
339 message_id = 0;
340 group_generation = 0;
341 GNUNET_assert (
342 GNUNET_OK == db->counters_message_get (db->cls, &channel_pub_key,
343 &fragment_id, &message_id,
344 &group_generation)
345 && fragment_id == GNUNET_ntohll (msg1->fragment_id)
346 && message_id == GNUNET_ntohll (msg1->message_id)
347 && group_generation == GNUNET_ntohll (msg1->group_generation));
348
349 /* Modify state */
350
351 LOG (GNUNET_ERROR_TYPE_INFO, "STATE\n");
352
353 LOG (GNUNET_ERROR_TYPE_INFO, "state_modify_*()\n");
354
355 message_id = GNUNET_ntohll (fcls.msg[0]->message_id) + 1;
356 GNUNET_assert (GNUNET_OK == db->state_modify_begin (db->cls, &channel_pub_key,
357 message_id, 0));
358
359 GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key,
360 GNUNET_PSYC_OP_ASSIGN,
361 "_foo",
362 C2ARG("one two three")));
363
364 GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key,
365 GNUNET_PSYC_OP_ASSIGN,
366 "_foo_bar", slave_key,
367 sizeof (*slave_key)));
368
369 GNUNET_assert (GNUNET_OK == db->state_modify_end (db->cls, &channel_pub_key,
370 message_id));
371
372 LOG (GNUNET_ERROR_TYPE_INFO, "state_get()\n");
373
374 struct StateClosure scls = { 0 };
375 scls.n = 0;
376 scls.value[0] = "one two three";
377 scls.value_size[0] = strlen ("one two three");
378
379 GNUNET_assert (GNUNET_OK == db->state_get (db->cls, &channel_pub_key, "_foo",
380 state_cb, &scls));
381 GNUNET_assert (scls.n == 1);
382
383 LOG (GNUNET_ERROR_TYPE_INFO, "state_get_prefix()\n");
384
385 scls.n = 0;
386 scls.value[1] = slave_key;
387 scls.value_size[1] = sizeof (*slave_key);
388
389 GNUNET_assert (GNUNET_OK == db->state_get_prefix (db->cls, &channel_pub_key,
390 "_foo", state_cb, &scls));
391 GNUNET_assert (scls.n == 2);
392
393 LOG (GNUNET_ERROR_TYPE_INFO, "state_get_signed()\n");
394
395 scls.n = 0;
396 GNUNET_assert (GNUNET_NO == db->state_get_signed (db->cls, &channel_pub_key,
397 state_cb, &scls));
398 GNUNET_assert (scls.n == 0);
399
400 LOG (GNUNET_ERROR_TYPE_INFO, "state_update_signed()\n");
401
402 GNUNET_assert (GNUNET_OK == db->state_update_signed (db->cls,
403 &channel_pub_key));
404
405 LOG (GNUNET_ERROR_TYPE_INFO, "state_get_signed()\n");
406
407 scls.n = 0;
408 GNUNET_assert (GNUNET_YES == db->state_get_signed (db->cls, &channel_pub_key,
409 state_cb, &scls));
410 GNUNET_assert (scls.n == 2);
411
412 /* State counters */
413
414 LOG (GNUNET_ERROR_TYPE_INFO, "counters_state_get()\n");
415
416 uint64_t max_state_msg_id = 0;
417 GNUNET_assert (GNUNET_OK == db->counters_state_get (db->cls, &channel_pub_key,
418 &max_state_msg_id)
419 && max_state_msg_id == message_id);
420
421 /* State sync */
422
423 LOG (GNUNET_ERROR_TYPE_INFO, "state_sync_*()\n");
424
425 scls.n = 0;
426 scls.value[0] = channel_key;
427 scls.value_size[0] = sizeof (*channel_key);
428 scls.value[1] = "three two one";
429 scls.value_size[1] = strlen ("three two one");
430
431 GNUNET_assert (GNUNET_OK == db->state_sync_begin (db->cls, &channel_pub_key));
432
433 GNUNET_assert (GNUNET_OK == db->state_sync_assign (db->cls, &channel_pub_key,
434 "_sync_bar", scls.value[0],
435 scls.value_size[0]));
436
437 GNUNET_assert (GNUNET_OK == db->state_sync_assign (db->cls, &channel_pub_key,
438 "_sync_foo", scls.value[1],
439 scls.value_size[1]));
440
441 GNUNET_assert (GNUNET_OK == db->state_sync_end (db->cls, &channel_pub_key,
442 max_state_msg_id,
443 INT64_MAX - 5));
444
445 GNUNET_assert (GNUNET_NO == db->state_get_prefix (db->cls, &channel_pub_key,
446 "_foo", state_cb, &scls));
447 GNUNET_assert (scls.n == 0);
448
449 GNUNET_assert (GNUNET_OK == db->state_get_prefix (db->cls, &channel_pub_key,
450 "_sync", state_cb, &scls));
451 GNUNET_assert (scls.n == 2);
452
453 scls.n = 0;
454 GNUNET_assert (GNUNET_OK == db->state_get_signed (db->cls, &channel_pub_key,
455 state_cb, &scls));
456 GNUNET_assert (scls.n == 2);
457
458 /* Modify state after sync */
459
460 LOG (GNUNET_ERROR_TYPE_INFO, "state_modify_*()\n");
461
462 message_id = GNUNET_ntohll (fcls.msg[0]->message_id) + 6;
463 GNUNET_assert (GNUNET_OK == db->state_modify_begin (db->cls, &channel_pub_key,
464 message_id,
465 message_id - max_state_msg_id));
466
467 GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key,
468 GNUNET_PSYC_OP_ASSIGN,
469 "_sync_foo",
470 C2ARG("five six seven")));
471
472 GNUNET_assert (GNUNET_OK == db->state_modify_end (db->cls, &channel_pub_key,
473 message_id));
474
475 /* Reset state */
476
477 LOG (GNUNET_ERROR_TYPE_INFO, "state_reset()\n");
478
479 scls.n = 0;
480 GNUNET_assert (GNUNET_OK == db->state_reset (db->cls, &channel_pub_key));
481 GNUNET_assert (scls.n == 0);
482
483 ok = 0;
484
485 if (NULL != channel_key)
486 {
487 GNUNET_free (channel_key);
488 channel_key = NULL;
489 }
490 if (NULL != slave_key)
491 {
492 GNUNET_free (slave_key);
493 slave_key = NULL;
494 }
495
496 unload_plugin (db);
497}
498
499
500int
501main (int argc, char *argv[])
502{
503 char cfg_name[128];
504 char *const xargv[] = {
505 "test-plugin-psycstore",
506 "-c", cfg_name,
507 "-L", LOG_LEVEL,
508 NULL
509 };
510 struct GNUNET_GETOPT_CommandLineOption options[] = {
511 GNUNET_GETOPT_OPTION_END
512 };
513 GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-psycstore-sqlite");
514 GNUNET_log_setup ("test-plugin-psycstore", LOG_LEVEL, NULL);
515 plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
516 GNUNET_snprintf (cfg_name, sizeof (cfg_name), "test_plugin_psycstore_%s.conf",
517 plugin_name);
518 GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1, xargv,
519 "test-plugin-psycstore", "nohelp", options, &run, NULL);
520
521 if ( (0 != ok) &&
522 (77 != ok) )
523 FPRINTF (stderr, "Missed some testcases: %d\n", ok);
524
525#if ! DEBUG_PSYCSTORE
526 GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-psycstore-sqlite");
527#endif
528
529 return ok;
530}
531
532/* 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 @@
1[psycstore-mysql]
2DATABASE = test
3# CONFIG = ~/.my.cnf
4# USER = gnunet
5# PASSWORD =
6# HOST = localhost
7# 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 @@
1[psycstore-postgres]
2CONFIG = 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 @@
1[psycstore-sqlite]
2FILENAME = $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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file psycstore/test_psycstore.c
23 * @brief Test for the PSYCstore service.
24 * @author Gabor X Toth
25 * @author Christian Grothoff
26 */
27
28#include <inttypes.h>
29
30#include "platform.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_common.h"
33#include "gnunet_testing_lib.h"
34#include "gnunet_psycstore_service.h"
35
36#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
37
38
39/**
40 * Return value from 'main'.
41 */
42static int res;
43
44/**
45 * Handle to PSYCstore service.
46 */
47static struct GNUNET_PSYCSTORE_Handle *h;
48
49/**
50 * Handle to PSYCstore operation.
51 */
52static struct GNUNET_PSYCSTORE_OperationHandle *op;
53
54/**
55 * Handle for task for timeout termination.
56 */
57static struct GNUNET_SCHEDULER_Task *end_badly_task;
58
59static struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key;
60static struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key;
61
62static struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key;
63static struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key;
64
65static struct FragmentClosure
66{
67 uint8_t n;
68 uint8_t n_expected;
69 uint64_t flags[16];
70 struct GNUNET_MULTICAST_MessageHeader *msg[16];
71} fcls;
72
73struct StateClosure {
74 size_t n;
75 char *name[16];
76 void *value[16];
77 size_t value_size[16];
78} scls;
79
80static struct GNUNET_PSYC_Modifier modifiers[16];
81
82/**
83 * Clean up all resources used.
84 */
85static void
86cleanup ()
87{
88 if (NULL != op)
89 {
90 GNUNET_PSYCSTORE_operation_cancel (op);
91 op = NULL;
92 }
93 if (NULL != h)
94 {
95 GNUNET_PSYCSTORE_disconnect (h);
96 h = NULL;
97 }
98 if (NULL != channel_key)
99 {
100 GNUNET_free (channel_key);
101 channel_key = NULL;
102 }
103 if (NULL != slave_key)
104 {
105 GNUNET_free (slave_key);
106 slave_key = NULL;
107 }
108 GNUNET_SCHEDULER_shutdown ();
109}
110
111
112/**
113 * Terminate the testcase (failure).
114 *
115 * @param cls NULL
116 */
117static void
118end_badly (void *cls)
119{
120 res = 1;
121 cleanup ();
122}
123
124
125/**
126 * Terminate the testcase (success).
127 *
128 * @param cls NULL
129 */
130static void
131end_normally (void *cls)
132{
133 res = 0;
134 cleanup ();
135}
136
137
138/**
139 * Finish the testcase (successfully).
140 */
141static void
142end ()
143{
144 if (NULL != end_badly_task)
145 {
146 GNUNET_SCHEDULER_cancel (end_badly_task);
147 end_badly_task = NULL;
148 }
149 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
150 &end_normally, NULL);
151}
152
153
154static void
155state_reset_result (void *cls,
156 int64_t result,
157 const char *err_msg,
158 uint16_t err_msg_size)
159{
160 op = NULL;
161 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
162 "state_reset_result:\t%d\n",
163 (int) result);
164 GNUNET_assert (GNUNET_OK == result);
165
166 op = GNUNET_PSYCSTORE_state_reset (h, &channel_pub_key,
167 &state_reset_result, cls);
168 GNUNET_PSYCSTORE_operation_cancel (op);
169 op = NULL;
170 end ();
171}
172
173
174static int
175state_result (void *cls,
176 const char *name,
177 const void *value,
178 uint32_t value_size)
179{
180 struct StateClosure *scls = cls;
181 const char *nam = scls->name[scls->n];
182 const void *val = scls->value[scls->n];
183 size_t val_size = scls->value_size[scls->n++];
184
185 if (value_size == val_size
186 && 0 == memcmp (value, val, val_size)
187 && 0 == strcmp (name, nam))
188 {
189 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
190 " variable %s matches\n",
191 name);
192 return GNUNET_YES;
193 }
194 else
195 {
196 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
197 " variable %s differs\nReceived: %.*s\nExpected: %.*s\n",
198 name, (int) value_size, (char*) value, (int) val_size, (char*) val);
199 GNUNET_assert (0);
200 return GNUNET_SYSERR;
201 }
202}
203
204
205static void
206state_get_prefix_result (void *cls, int64_t result,
207 const char *err_msg, uint16_t err_msg_size)
208{
209 struct StateClosure *scls = cls;
210 op = NULL;
211 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "state_get_prefix_result:\t%ld\n", (long int) result);
212 GNUNET_assert (GNUNET_OK == result && 2 == scls->n);
213
214 op = GNUNET_PSYCSTORE_state_reset (h, &channel_pub_key,
215 &state_reset_result, cls);
216}
217
218
219static void
220state_get_result (void *cls, int64_t result,
221 const char *err_msg, uint16_t err_msg_size)
222{
223 op = NULL;
224 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "state_get_result:\t%ld\n", (long int) result);
225 GNUNET_assert (GNUNET_OK == result);
226
227 scls.n = 0;
228
229 scls.name[0] = "_sync_bar";
230 scls.value[0] = "ten eleven twelve";
231 scls.value_size[0] = sizeof ("ten eleven twelve") - 1;
232
233 scls.name[1] = "_sync_foo";
234 scls.value[1] = "three two one";
235 scls.value_size[1] = sizeof ("three two one") - 1;
236
237 op = GNUNET_PSYCSTORE_state_get_prefix (h, &channel_pub_key, "_sync",
238 &state_result,
239 &state_get_prefix_result, &scls);
240}
241
242
243static void
244counters_result (void *cls, int status, uint64_t max_fragment_id,
245 uint64_t max_message_id, uint64_t max_group_generation,
246 uint64_t max_state_message_id)
247{
248 struct FragmentClosure *fcls = cls;
249 int result = 0;
250 op = NULL;
251
252 if (GNUNET_OK == status
253 && max_fragment_id == GNUNET_ntohll (fcls->msg[2]->fragment_id)
254 && max_message_id == GNUNET_ntohll (fcls->msg[2]->message_id)
255 && max_group_generation == GNUNET_ntohll (fcls->msg[2]->group_generation)
256 && max_state_message_id == GNUNET_ntohll (fcls->msg[0]->message_id))
257 result = 1;
258
259 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "counters_get:\t%d\n", result);
260 GNUNET_assert (result == 1);
261
262 scls.n = 0;
263 scls.name[0] = "_sync_bar";
264 scls.value[0] = "ten eleven twelve";
265 scls.value_size[0] = sizeof ("ten eleven twelve") - 1;
266
267 op = GNUNET_PSYCSTORE_state_get (h, &channel_pub_key, "_sync_bar_x_yy_zzz",
268 &state_result, &state_get_result, &scls);
269}
270
271
272static void
273state_modify_result (void *cls, int64_t result,
274 const char *err_msg, uint16_t err_msg_size)
275{
276 op = NULL;
277 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "state_modify_result:\t%ld\n", (long int) result);
278 GNUNET_assert (GNUNET_OK == result);
279
280 op = GNUNET_PSYCSTORE_counters_get (h, &channel_pub_key,
281 &counters_result, cls);
282}
283
284
285static void
286state_sync_result (void *cls, int64_t result,
287 const char *err_msg, uint16_t err_msg_size)
288{
289 struct FragmentClosure *fcls = cls;
290 op = NULL;
291 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "state_sync_result:\t%ld\n", (long int) result);
292 GNUNET_assert (GNUNET_OK == result);
293
294 op = GNUNET_PSYCSTORE_state_modify (h, &channel_pub_key,
295 GNUNET_ntohll (fcls->msg[0]->message_id),
296 0, state_modify_result, fcls);
297}
298
299
300static int
301fragment_result (void *cls,
302 struct GNUNET_MULTICAST_MessageHeader *msg,
303 enum GNUNET_PSYCSTORE_MessageFlags flags)
304{
305 struct FragmentClosure *fcls = cls;
306 GNUNET_assert (fcls->n < fcls->n_expected);
307 struct GNUNET_MULTICAST_MessageHeader *msg0 = fcls->msg[fcls->n];
308 uint64_t flags0 = fcls->flags[fcls->n++];
309
310 if (flags == flags0 && msg->header.size == msg0->header.size
311 && 0 == memcmp (msg, msg0, ntohs (msg->header.size)))
312 {
313 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " fragment %" PRIu64 " matches\n",
314 GNUNET_ntohll (msg->fragment_id));
315 return GNUNET_YES;
316 }
317 else
318 {
319 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
320 " fragment differs: expected %" PRIu64 ", got %" PRIu64 "\n",
321 GNUNET_ntohll (msg0->fragment_id),
322 GNUNET_ntohll (msg->fragment_id));
323 GNUNET_assert (0);
324 return GNUNET_SYSERR;
325 }
326}
327
328
329static void
330message_get_latest_result (void *cls, int64_t result,
331 const char *err_msg, uint16_t err_msg_size)
332{
333 struct FragmentClosure *fcls = cls;
334 op = NULL;
335 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "message_get_latest:\t%ld\n", (long int) result);
336 GNUNET_assert (0 < result && fcls->n == fcls->n_expected);
337
338 modifiers[0] = (struct GNUNET_PSYC_Modifier) {
339 .oper = '=',
340 .name = "_sync_foo",
341 .value = "three two one",
342 .value_size = sizeof ("three two one") - 1
343 };
344 modifiers[1] = (struct GNUNET_PSYC_Modifier) {
345 .oper = '=',
346 .name = "_sync_bar",
347 .value = "ten eleven twelve",
348 .value_size = sizeof ("ten eleven twelve") - 1
349 };
350
351 op = GNUNET_PSYCSTORE_state_sync (h, &channel_pub_key,
352 GNUNET_ntohll (fcls->msg[0]->message_id) + 1,
353 GNUNET_ntohll (fcls->msg[0]->message_id) + 2,
354 2, modifiers, state_sync_result, fcls);
355}
356
357
358static void
359message_get_result (void *cls, int64_t result,
360 const char *err_msg, uint16_t err_msg_size)
361{
362 struct FragmentClosure *fcls = cls;
363 op = NULL;
364 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "message_get:\t%ld\n", (long int) result);
365 GNUNET_assert (0 < result && fcls->n == fcls->n_expected);
366
367 fcls->n = 0;
368 fcls->n_expected = 3;
369 op = GNUNET_PSYCSTORE_message_get_latest (h, &channel_pub_key, &slave_pub_key,
370 1, "", &fragment_result,
371 &message_get_latest_result, fcls);
372}
373
374
375static void
376message_get_fragment_result (void *cls, int64_t result,
377 const char *err_msg, uint16_t err_msg_size)
378{
379 struct FragmentClosure *fcls = cls;
380 op = NULL;
381 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "message_get_fragment:\t%ld\n", (long int) result);
382 GNUNET_assert (0 < result && fcls->n == fcls->n_expected);
383
384 fcls->n = 0;
385 fcls->n_expected = 3;
386 uint64_t message_id = GNUNET_ntohll (fcls->msg[0]->message_id);
387 op = GNUNET_PSYCSTORE_message_get (h, &channel_pub_key, &slave_pub_key,
388 message_id, message_id, 0, "",
389 &fragment_result,
390 &message_get_result, fcls);
391}
392
393
394static void
395fragment_get_latest_result (void *cls, int64_t result,
396 const char *err_msg, uint16_t err_msg_size)
397{
398 struct FragmentClosure *fcls = cls;
399 op = NULL;
400 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "fragment_get_latest:\t%ld\n", (long int) result);
401 GNUNET_assert (0 < result && fcls->n == fcls->n_expected);
402
403 fcls->n = 1;
404 fcls->n_expected = 2;
405 op = GNUNET_PSYCSTORE_message_get_fragment (h, &channel_pub_key, &slave_pub_key,
406 GNUNET_ntohll (fcls->msg[1]->message_id),
407 GNUNET_ntohll (fcls->msg[1]->fragment_offset),
408 &fragment_result,
409 &message_get_fragment_result, fcls);
410}
411
412
413static void
414fragment_get_result (void *cls, int64_t result,
415 const char *err_msg, uint16_t err_msg_size)
416{
417 struct FragmentClosure *fcls = cls;
418 op = NULL;
419 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
420 "fragment_get:\t%d\n",
421 (int) result);
422 GNUNET_assert (0 < result && fcls->n == fcls->n_expected);
423
424 fcls->n = 0;
425 fcls->n_expected = 3;
426 op = GNUNET_PSYCSTORE_fragment_get_latest (h, &channel_pub_key,
427 &slave_pub_key, fcls->n_expected,
428 &fragment_result,
429 &fragment_get_latest_result, fcls);
430}
431
432
433static void
434fragment_store_result (void *cls, int64_t result,
435 const char *err_msg, uint16_t err_msg_size)
436{
437 op = NULL;
438 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "fragment_store:\t%ld\n", (long int) result);
439 GNUNET_assert (GNUNET_OK == result);
440
441 if ((intptr_t) cls == GNUNET_YES)
442 { /* last fragment */
443 fcls.n = 0;
444 fcls.n_expected = 1;
445 uint64_t fragment_id = GNUNET_ntohll (fcls.msg[0]->fragment_id);
446 op = GNUNET_PSYCSTORE_fragment_get (h, &channel_pub_key, &slave_pub_key,
447 fragment_id, fragment_id,
448 &fragment_result,
449 &fragment_get_result, &fcls);
450 }
451}
452
453
454static void
455fragment_store ()
456{
457 struct GNUNET_MULTICAST_MessageHeader *msg;
458 fcls.flags[0] = GNUNET_PSYCSTORE_MESSAGE_STATE;
459 fcls.msg[0] = msg = GNUNET_malloc (sizeof (*msg) + sizeof (channel_pub_key));
460 GNUNET_assert (msg != NULL);
461
462 msg->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE);
463 msg->header.size = htons (sizeof (*msg) + sizeof (channel_pub_key));
464
465 msg->hop_counter = htonl (9);
466 msg->fragment_id = GNUNET_htonll (INT64_MAX - 8);
467 msg->fragment_offset = GNUNET_htonll (0);
468 msg->message_id = GNUNET_htonll (INT64_MAX - 10);
469 msg->group_generation = GNUNET_htonll (INT64_MAX - 3);
470 msg->flags = htonl (GNUNET_MULTICAST_MESSAGE_LAST_FRAGMENT);
471
472 GNUNET_memcpy (&msg[1], &channel_pub_key, sizeof (channel_pub_key));
473
474 msg->purpose.size = htonl (ntohs (msg->header.size)
475 - sizeof (msg->header)
476 - sizeof (msg->hop_counter)
477 - sizeof (msg->signature));
478 msg->purpose.purpose = htonl (234);
479 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (channel_key, &msg->purpose,
480 &msg->signature));
481
482 op = GNUNET_PSYCSTORE_fragment_store (h, &channel_pub_key, msg, fcls.flags[0],
483 &fragment_store_result, GNUNET_NO);
484
485 fcls.flags[1] = GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED;
486 fcls.msg[1] = msg = GNUNET_malloc (sizeof (*msg) + sizeof (channel_pub_key));
487 GNUNET_memcpy (msg, fcls.msg[0], sizeof (*msg) + sizeof (channel_pub_key));
488 msg->fragment_id = GNUNET_htonll (INT64_MAX - 4);
489 msg->fragment_offset = GNUNET_htonll (1024);
490
491 op = GNUNET_PSYCSTORE_fragment_store (h, &channel_pub_key, msg, fcls.flags[1],
492 &fragment_store_result, GNUNET_NO);
493
494 fcls.flags[2] = GNUNET_PSYCSTORE_MESSAGE_STATE_HASH;
495 fcls.msg[2] = msg = GNUNET_malloc (sizeof (*msg) + sizeof (channel_pub_key));
496 GNUNET_memcpy (msg, fcls.msg[1], sizeof (*msg) + sizeof (channel_pub_key));
497 msg->fragment_id = GNUNET_htonll (INT64_MAX);
498 msg->fragment_offset = GNUNET_htonll (16384);
499
500 op = GNUNET_PSYCSTORE_fragment_store (h, &channel_pub_key, msg, fcls.flags[2],
501 &fragment_store_result, (void *) GNUNET_YES);
502}
503
504
505static void
506membership_test_result (void *cls, int64_t result,
507 const char *err_msg, uint16_t err_msg_size)
508{
509 op = NULL;
510 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "membership_test:\t%ld\n", (long int) result);
511 GNUNET_assert (GNUNET_OK == result);
512
513 fragment_store ();
514}
515
516
517static void
518membership_store_result (void *cls, int64_t result,
519 const char *err_msg, uint16_t err_msg_size)
520{
521 op = NULL;
522 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "membership_store:\t%ld\n", (long int) result);
523 GNUNET_assert (GNUNET_OK == result);
524
525 op = GNUNET_PSYCSTORE_membership_test (h, &channel_pub_key, &slave_pub_key,
526 INT64_MAX - 10, 2,
527 &membership_test_result, NULL);
528}
529
530
531/**
532 * Main function of the test, run from scheduler.
533 *
534 * @param cls NULL
535 * @param cfg configuration we use (also to connect to PSYCstore service)
536 * @param peer handle to access more of the peer (not used)
537 */
538static void
539#if DEBUG_TEST_PSYCSTORE
540run (void *cls, char *const *args, const char *cfgfile,
541 const struct GNUNET_CONFIGURATION_Handle *cfg)
542#else
543run (void *cls,
544 const struct GNUNET_CONFIGURATION_Handle *cfg,
545 struct GNUNET_TESTING_Peer *peer)
546#endif
547{
548 end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
549
550 h = GNUNET_PSYCSTORE_connect (cfg);
551 GNUNET_assert (NULL != h);
552
553 channel_key = GNUNET_CRYPTO_eddsa_key_create ();
554 slave_key = GNUNET_CRYPTO_ecdsa_key_create ();
555
556 GNUNET_CRYPTO_eddsa_key_get_public (channel_key, &channel_pub_key);
557 GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key);
558
559 op = GNUNET_PSYCSTORE_membership_store (h, &channel_pub_key, &slave_pub_key,
560 GNUNET_YES, INT64_MAX - 5,
561 INT64_MAX - 10, 2,
562 &membership_store_result, NULL);
563}
564
565
566int
567main (int argc, char *argv[])
568{
569 res = 1;
570#if DEBUG_TEST_PSYCSTORE
571 const struct GNUNET_GETOPT_CommandLineOption opts[] = {
572 GNUNET_GETOPT_OPTION_END
573 };
574 if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-psycstore",
575 "test-psycstore [options]",
576 opts, &run, NULL))
577 return 1;
578#else
579 if (0 != GNUNET_TESTING_service_run ("test-psycstore", "psycstore",
580 "test_psycstore.conf", &run, NULL))
581 return 1;
582#endif
583 return res;
584}
585
586/* 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 @@
1[PATHS]
2GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-psycstore/
3
4[psycstore]
5DATABASE = sqlite
6
7[psycstore-sqlite]
8FILENAME = $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 @@
1test_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 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4pkgcfgdir= $(pkgdatadir)/config.d/
5
6libexecdir= $(pkglibdir)/libexec/
7
8if MINGW
9 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
10endif
11
12if USE_COVERAGE
13 AM_CFLAGS = --coverage -O0
14 XLIB = -lgcov
15endif
16
17lib_LTLIBRARIES = libgnunetpsycutil.la
18
19libgnunetpsycutil_la_SOURCES = \
20 psyc_env.c \
21 psyc_message.c \
22 psyc_slicer.c
23libgnunetpsycutil_la_LIBADD = \
24 $(top_builddir)/src/util/libgnunetutil.la \
25 $(GN_LIBINTL) $(XLIB)
26libgnunetpsycutil_la_LDFLAGS = \
27 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
28 -version-info 0:0:0
29
30if HAVE_TESTING
31check_PROGRAMS = \
32 test_psyc_env
33endif
34
35if ENABLE_TEST_RUN
36AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
37TESTS = $(check_PROGRAMS)
38endif
39
40test_psyc_env_SOURCES = \
41 test_psyc_env.c
42test_psyc_env_LDADD = \
43 libgnunetpsycutil.la \
44 $(top_builddir)/src/testing/libgnunettesting.la \
45 $(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 @@
1/*
2 * This file is part of GNUnet.
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @author Gabor X Toth
23 *
24 * @file
25 * Library providing operations for the @e environment of
26 * PSYC and Social messages.
27 */
28
29#include "platform.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_psyc_env.h"
32
33/**
34 * Environment for a message.
35 *
36 * Contains modifiers.
37 */
38struct GNUNET_PSYC_Environment
39{
40 struct GNUNET_PSYC_Modifier *mod_head;
41 struct GNUNET_PSYC_Modifier *mod_tail;
42 size_t mod_count;
43};
44
45
46/**
47 * Create an environment.
48 *
49 * @return A newly allocated environment.
50 */
51struct GNUNET_PSYC_Environment *
52GNUNET_PSYC_env_create ()
53{
54 return GNUNET_new (struct GNUNET_PSYC_Environment);
55}
56
57
58/**
59 * Add a modifier to the environment.
60 *
61 * @param env The environment.
62 * @param oper Operation to perform.
63 * @param name Name of the variable.
64 * @param value Value of the variable.
65 * @param value_size Size of @a value.
66 */
67void
68GNUNET_PSYC_env_add (struct GNUNET_PSYC_Environment *env,
69 enum GNUNET_PSYC_Operator oper, const char *name,
70 const void *value, size_t value_size)
71{
72 struct GNUNET_PSYC_Modifier *mod = GNUNET_new (struct GNUNET_PSYC_Modifier);
73 mod->oper = oper;
74 mod->name = name;
75 mod->value = value;
76 mod->value_size = value_size;
77 GNUNET_CONTAINER_DLL_insert_tail (env->mod_head, env->mod_tail, mod);
78 env->mod_count++;
79}
80
81
82/**
83 * Get the first modifier of the environment.
84 */
85struct GNUNET_PSYC_Modifier *
86GNUNET_PSYC_env_head (const struct GNUNET_PSYC_Environment *env)
87{
88 return env->mod_head;
89}
90
91
92/**
93 * Get the last modifier of the environment.
94 */
95struct GNUNET_PSYC_Modifier *
96GNUNET_PSYC_env_tail (const struct GNUNET_PSYC_Environment *env)
97{
98 return env->mod_tail;
99}
100
101
102/**
103 * Remove a modifier from the environment.
104 */
105void
106GNUNET_PSYC_env_remove (struct GNUNET_PSYC_Environment *env,
107 struct GNUNET_PSYC_Modifier *mod)
108{
109 GNUNET_CONTAINER_DLL_remove (env->mod_head, env->mod_tail, mod);
110}
111
112
113/**
114 * Get the modifier at the beginning of an environment and remove it.
115 *
116 * @param env
117 * @param oper
118 * @param name
119 * @param value
120 * @param value_size
121 *
122 * @return
123 */
124int
125GNUNET_PSYC_env_shift (struct GNUNET_PSYC_Environment *env,
126 enum GNUNET_PSYC_Operator *oper, const char **name,
127 const void **value, size_t *value_size)
128{
129 if (NULL == env->mod_head)
130 return GNUNET_NO;
131
132 struct GNUNET_PSYC_Modifier *mod = env->mod_head;
133 *oper = mod->oper;
134 *name = mod->name;
135 *value = mod->value;
136 *value_size = mod->value_size;
137
138 GNUNET_CONTAINER_DLL_remove (env->mod_head, env->mod_tail, mod);
139 GNUNET_free (mod);
140 env->mod_count--;
141
142 return GNUNET_YES;
143}
144
145
146/**
147 * Iterate through all modifiers in the environment.
148 *
149 * @param env The environment.
150 * @param it Iterator.
151 * @param it_cls Closure for iterator.
152 */
153void
154GNUNET_PSYC_env_iterate (const struct GNUNET_PSYC_Environment *env,
155 GNUNET_PSYC_Iterator it, void *it_cls)
156{
157 struct GNUNET_PSYC_Modifier *mod;
158 for (mod = env->mod_head; NULL != mod; mod = mod->next)
159 it (it_cls, mod->oper, mod->name, mod->value, mod->value_size);
160}
161
162
163/**
164 * Get the number of modifiers in the environment.
165 *
166 * @param env The environment.
167 *
168 * @return Number of modifiers.
169 */
170size_t
171GNUNET_PSYC_env_get_count (const struct GNUNET_PSYC_Environment *env)
172{
173 return env->mod_count;
174}
175
176
177/**
178 * Destroy an environment.
179 *
180 * @param env The environment to destroy.
181 */
182void
183GNUNET_PSYC_env_destroy (struct GNUNET_PSYC_Environment *env)
184{
185 struct GNUNET_PSYC_Modifier *mod, *prev = NULL;
186 for (mod = env->mod_head; NULL != mod; mod = mod->next)
187 {
188 if (NULL != prev)
189 GNUNET_free (prev);
190 prev = mod;
191 }
192 if (NULL != prev)
193 GNUNET_free (prev);
194
195 GNUNET_free (env);
196}
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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file psycutil/psyc_message.c
23 * @brief PSYC utilities; receiving/transmitting/logging PSYC messages.
24 * @author Gabor X Toth
25 */
26
27#include <inttypes.h>
28
29#include "platform.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_psyc_util_lib.h"
32#include "gnunet_psyc_service.h"
33
34#define LOG(kind,...) GNUNET_log_from (kind, "psyc-util",__VA_ARGS__)
35
36
37struct GNUNET_PSYC_TransmitHandle
38{
39 /**
40 * Client connection to service.
41 */
42 struct GNUNET_MQ_Handle *mq;
43
44 /**
45 * Message currently being received from the client.
46 */
47 struct GNUNET_MessageHeader *msg;
48
49 /**
50 * Envelope for @a msg
51 */
52 struct GNUNET_MQ_Envelope *env;
53
54 /**
55 * Callback to request next modifier from client.
56 */
57 GNUNET_PSYC_TransmitNotifyModifier notify_mod;
58
59 /**
60 * Closure for the notify callbacks.
61 */
62 void *notify_mod_cls;
63
64 /**
65 * Callback to request next data fragment from client.
66 */
67 GNUNET_PSYC_TransmitNotifyData notify_data;
68
69 /**
70 * Closure for the notify callbacks.
71 */
72 void *notify_data_cls;
73
74 /**
75 * Modifier of the environment that is currently being transmitted.
76 */
77 struct GNUNET_PSYC_Modifier *mod;
78
79 /**
80 *
81 */
82 const char *mod_value;
83
84 /**
85 * Number of bytes remaining to be transmitted from the current modifier value.
86 */
87 uint32_t mod_value_remaining;
88
89 /**
90 * State of the current message being received from client.
91 */
92 enum GNUNET_PSYC_MessageState state;
93
94 /**
95 * Number of PSYC_TRANSMIT_ACK messages we are still waiting for.
96 */
97 uint8_t acks_pending;
98
99 /**
100 * Is transmission paused?
101 */
102 uint8_t paused;
103
104 /**
105 * Are we currently transmitting a message?
106 */
107 uint8_t in_transmit;
108
109 /**
110 * Notify callback is currently being called.
111 */
112 uint8_t in_notify;
113
114};
115
116
117
118struct GNUNET_PSYC_ReceiveHandle
119{
120 /**
121 * Message callback.
122 */
123 GNUNET_PSYC_MessageCallback message_cb;
124
125 /**
126 * Message part callback.
127 */
128 GNUNET_PSYC_MessagePartCallback message_part_cb;
129
130 /**
131 * Closure for the callbacks.
132 */
133 void *cb_cls;
134
135 /**
136 * ID of the message being received from the PSYC service.
137 */
138 uint64_t message_id;
139
140 /**
141 * Public key of the slave from which a message is being received.
142 */
143 struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key;
144
145 /**
146 * State of the currently being received message from the PSYC service.
147 */
148 enum GNUNET_PSYC_MessageState state;
149
150 /**
151 * Flags for the currently being received message from the PSYC service.
152 */
153 enum GNUNET_PSYC_MessageFlags flags;
154
155 /**
156 * Expected value size for the modifier being received from the PSYC service.
157 */
158 uint32_t mod_value_size_expected;
159
160 /**
161 * Actual value size for the modifier being received from the PSYC service.
162 */
163 uint32_t mod_value_size;
164};
165
166
167/**** Messages ****/
168
169
170/**
171 * Create a PSYC message.
172 *
173 * @param method_name
174 * PSYC method for the message.
175 * @param env
176 * Environment for the message.
177 * @param data
178 * Data payload for the message.
179 * @param data_size
180 * Size of @a data.
181 *
182 * @return Message header with size information,
183 * followed by the message parts.
184 */
185struct GNUNET_PSYC_Message *
186GNUNET_PSYC_message_create (const char *method_name,
187 const struct GNUNET_PSYC_Environment *env,
188 const void *data,
189 size_t data_size)
190{
191 struct GNUNET_PSYC_Modifier *mod = NULL;
192 struct GNUNET_PSYC_MessageMethod *pmeth = NULL;
193 struct GNUNET_PSYC_MessageModifier *pmod = NULL;
194 struct GNUNET_MessageHeader *pmsg = NULL;
195 uint16_t env_size = 0;
196 if (NULL != env)
197 {
198 mod = GNUNET_PSYC_env_head (env);
199 while (NULL != mod)
200 {
201 env_size += sizeof (*pmod) + strlen (mod->name) + 1 + mod->value_size;
202 mod = mod->next;
203 }
204 }
205
206 struct GNUNET_PSYC_Message *msg;
207 uint16_t method_name_size = strlen (method_name) + 1;
208 if (method_name_size == 1)
209 return NULL;
210
211 uint16_t msg_size = sizeof (*msg) /* header */
212 + sizeof (*pmeth) + method_name_size /* method */
213 + env_size /* modifiers */
214 + ((0 < data_size) ? sizeof (*pmsg) + data_size : 0) /* data */
215 + sizeof (*pmsg); /* end of message */
216 msg = GNUNET_malloc (msg_size);
217 msg->header.size = htons (msg_size);
218 msg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); /* FIXME */
219
220 pmeth = (struct GNUNET_PSYC_MessageMethod *) &msg[1];
221 pmeth->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD);
222 pmeth->header.size = htons (sizeof (*pmeth) + method_name_size);
223 GNUNET_memcpy (&pmeth[1], method_name, method_name_size);
224
225 uint16_t p = sizeof (*msg) + sizeof (*pmeth) + method_name_size;
226 if (NULL != env)
227 {
228 mod = GNUNET_PSYC_env_head (env);
229 while (NULL != mod)
230 {
231 uint16_t mod_name_size = strlen (mod->name) + 1;
232 pmod = (struct GNUNET_PSYC_MessageModifier *) ((char *) msg + p);
233 pmod->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER);
234 pmod->header.size = sizeof (*pmod) + mod_name_size + mod->value_size;
235 p += pmod->header.size;
236 pmod->header.size = htons (pmod->header.size);
237
238 pmod->oper = mod->oper;
239 pmod->name_size = htons (mod_name_size);
240 pmod->value_size = htonl (mod->value_size);
241
242 GNUNET_memcpy (&pmod[1], mod->name, mod_name_size);
243 if (0 < mod->value_size)
244 GNUNET_memcpy ((char *) &pmod[1] + mod_name_size, mod->value, mod->value_size);
245
246 mod = mod->next;
247 }
248 }
249
250 if (0 < data_size)
251 {
252 pmsg = (struct GNUNET_MessageHeader *) ((char *) msg + p);
253 pmsg->size = sizeof (*pmsg) + data_size;
254 p += pmsg->size;
255 pmsg->size = htons (pmsg->size);
256 pmsg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA);
257 GNUNET_memcpy (&pmsg[1], data, data_size);
258 }
259
260 pmsg = (struct GNUNET_MessageHeader *) ((char *) msg + p);
261 pmsg->size = htons (sizeof (*pmsg));
262 pmsg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END);
263
264 GNUNET_assert (p + sizeof (*pmsg) == msg_size);
265 return msg;
266}
267
268
269void
270GNUNET_PSYC_log_message (enum GNUNET_ErrorType kind,
271 const struct GNUNET_MessageHeader *msg)
272{
273 uint16_t size = ntohs (msg->size);
274 uint16_t type = ntohs (msg->type);
275
276 GNUNET_log (kind,
277 "Message of type %d and size %u:\n",
278 type,
279 size);
280 switch (type)
281 {
282 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE:
283 {
284 const struct GNUNET_PSYC_MessageHeader *pmsg
285 = (const struct GNUNET_PSYC_MessageHeader *) msg;
286 GNUNET_log (kind,
287 "\tID: %" PRIu64 "\tflags: %x" PRIu32 "\n",
288 GNUNET_ntohll (pmsg->message_id),
289 ntohl (pmsg->flags));
290 break;
291 }
292 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
293 {
294 const struct GNUNET_PSYC_MessageMethod *meth
295 = (const struct GNUNET_PSYC_MessageMethod *) msg;
296 GNUNET_log (kind,
297 "\t%.*s\n",
298 (int) (size - sizeof (*meth)),
299 (const char *) &meth[1]);
300 break;
301 }
302 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
303 {
304 const struct GNUNET_PSYC_MessageModifier *mod
305 = (const struct GNUNET_PSYC_MessageModifier *) msg;
306 uint16_t name_size = ntohs (mod->name_size);
307 char oper = ' ' < mod->oper ? mod->oper : ' ';
308 GNUNET_log (kind,
309 "\t%c%.*s\t%.*s\n",
310 oper,
311 (int) name_size,
312 (const char *) &mod[1],
313 (int) (size - sizeof (*mod) - name_size),
314 ((const char *) &mod[1]) + name_size);
315 break;
316 }
317 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
318 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
319 GNUNET_log (kind,
320 "\t%.*s\n",
321 (int) (size - sizeof (*msg)),
322 (const char *) &msg[1]);
323 break;
324 }
325}
326
327
328/**** Transmitting messages ****/
329
330
331/**
332 * Create a transmission handle.
333 */
334struct GNUNET_PSYC_TransmitHandle *
335GNUNET_PSYC_transmit_create (struct GNUNET_MQ_Handle *mq)
336{
337 struct GNUNET_PSYC_TransmitHandle *tmit = GNUNET_new (struct GNUNET_PSYC_TransmitHandle);
338
339 tmit->mq = mq;
340 return tmit;
341}
342
343
344/**
345 * Destroy a transmission handle.
346 */
347void
348GNUNET_PSYC_transmit_destroy (struct GNUNET_PSYC_TransmitHandle *tmit)
349{
350 GNUNET_free (tmit);
351}
352
353
354/**
355 * Queue a message part for transmission.
356 *
357 * The message part is added to the current message buffer.
358 * When this buffer is full, it is added to the transmission queue.
359 *
360 * @param tmit
361 * Transmission handle.
362 * @param msg
363 * Message part, or NULL.
364 * @param tmit_now
365 * Transmit message now, or wait for buffer to fill up?
366 * #GNUNET_YES or #GNUNET_NO.
367 */
368static void
369transmit_queue_insert (struct GNUNET_PSYC_TransmitHandle *tmit,
370 const struct GNUNET_MessageHeader *msg,
371 uint8_t tmit_now)
372{
373 uint16_t size = (NULL != msg) ? ntohs (msg->size) : 0;
374
375 LOG (GNUNET_ERROR_TYPE_DEBUG,
376 "Queueing message part of type %u and size %u (tmit_now: %u)).\n",
377 NULL != msg ? ntohs (msg->type) : 0, size, tmit_now);
378
379 if (NULL != tmit->msg)
380 {
381 if (NULL == msg
382 || GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < tmit->msg->size + size)
383 {
384 /* End of message or buffer is full, add it to transmission queue
385 * and start with empty buffer */
386 tmit->msg->size = htons (tmit->msg->size);
387 GNUNET_MQ_send (tmit->mq, tmit->env);
388 tmit->env = NULL;
389 tmit->msg = NULL;
390 tmit->acks_pending++;
391 }
392 else
393 {
394 /* Message fits in current buffer, append */
395 GNUNET_memcpy ((char *) tmit->msg + tmit->msg->size, msg, size);
396 tmit->msg->size += size;
397 }
398 }
399
400 if (NULL == tmit->msg && NULL != msg)
401 {
402 /* Empty buffer, copy over message. */
403 tmit->env = GNUNET_MQ_msg_extra (tmit->msg,
404 GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD,
405 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE);
406 /* store current message size in host byte order
407 * then later switch it to network byte order before sending */
408 tmit->msg->size = sizeof (*tmit->msg) + size;
409
410 GNUNET_memcpy (&tmit->msg[1], msg, size);
411 }
412
413 if (NULL != tmit->msg
414 && (GNUNET_YES == tmit_now
415 || (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD
416 < tmit->msg->size + sizeof (struct GNUNET_MessageHeader))))
417 {
418 /* End of message or buffer is full, add it to transmission queue. */
419 tmit->msg->size = htons (tmit->msg->size);
420 GNUNET_MQ_send (tmit->mq, tmit->env);
421 tmit->env = NULL;
422 tmit->msg = NULL;
423 tmit->acks_pending++;
424 }
425}
426
427
428/**
429 * Request data from client to transmit.
430 *
431 * @param tmit Transmission handle.
432 */
433static void
434transmit_data (struct GNUNET_PSYC_TransmitHandle *tmit)
435{
436 int notify_ret = GNUNET_YES;
437 uint16_t data_size = 0;
438 char data[GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD] = "";
439 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) data;
440 msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA);
441
442 if (NULL != tmit->notify_data)
443 {
444 data_size = GNUNET_PSYC_DATA_MAX_PAYLOAD;
445 tmit->in_notify = GNUNET_YES;
446 notify_ret = tmit->notify_data (tmit->notify_data_cls, &data_size, &msg[1]);
447 tmit->in_notify = GNUNET_NO;
448 }
449 LOG (GNUNET_ERROR_TYPE_DEBUG,
450 "transmit_data (ret: %d, size: %u): %.*s\n",
451 notify_ret, data_size, data_size, &msg[1]);
452 switch (notify_ret)
453 {
454 case GNUNET_NO:
455 if (0 == data_size)
456 {
457 /* Transmission paused, nothing to send. */
458 tmit->paused = GNUNET_YES;
459 return;
460 }
461 break;
462
463 case GNUNET_YES:
464 tmit->state = GNUNET_PSYC_MESSAGE_STATE_END;
465 break;
466
467 default:
468 LOG (GNUNET_ERROR_TYPE_ERROR,
469 "TransmitNotifyData callback returned error when requesting data.\n");
470
471 tmit->state = GNUNET_PSYC_MESSAGE_STATE_CANCEL;
472 msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL);
473 msg->size = htons (sizeof (*msg));
474 transmit_queue_insert (tmit, msg, GNUNET_YES);
475 tmit->in_transmit = GNUNET_NO;
476 return;
477 }
478
479 if (0 < data_size)
480 {
481 GNUNET_assert (data_size <= GNUNET_PSYC_DATA_MAX_PAYLOAD);
482 msg->size = htons (sizeof (*msg) + data_size);
483 transmit_queue_insert (tmit, msg, !notify_ret);
484 }
485
486 /* End of message. */
487 if (GNUNET_YES == notify_ret)
488 {
489 msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END);
490 msg->size = htons (sizeof (*msg));
491 transmit_queue_insert (tmit, msg, GNUNET_YES);
492 /* FIXME: wait for ACK before setting in_transmit to no */
493 tmit->in_transmit = GNUNET_NO;
494 }
495}
496
497
498/**
499 * Request a modifier from a client to transmit.
500 *
501 * @param tmit Transmission handle.
502 */
503static void
504transmit_mod (struct GNUNET_PSYC_TransmitHandle *tmit)
505{
506 uint16_t max_data_size = 0;
507 uint16_t data_size = 0;
508 char data[GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD] = "";
509 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) data;
510 int notify_ret = GNUNET_YES;
511
512 switch (tmit->state)
513 {
514 case GNUNET_PSYC_MESSAGE_STATE_MODIFIER:
515 {
516 struct GNUNET_PSYC_MessageModifier *mod
517 = (struct GNUNET_PSYC_MessageModifier *) msg;
518 msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER);
519 msg->size = sizeof (struct GNUNET_PSYC_MessageModifier);
520
521 if (NULL != tmit->notify_mod)
522 {
523 max_data_size = GNUNET_PSYC_MODIFIER_MAX_PAYLOAD;
524 data_size = max_data_size;
525 tmit->in_notify = GNUNET_YES;
526 notify_ret = tmit->notify_mod (tmit->notify_mod_cls, &data_size, &mod[1],
527 &mod->oper, &mod->value_size);
528 tmit->in_notify = GNUNET_NO;
529 }
530
531 mod->name_size = strnlen ((char *) &mod[1], data_size) + 1;
532 LOG (GNUNET_ERROR_TYPE_DEBUG,
533 "transmit_mod (ret: %d, size: %u + %u): %.*s\n",
534 notify_ret, mod->name_size, mod->value_size, data_size, &mod[1]);
535 if (mod->name_size < data_size)
536 {
537 tmit->mod_value_remaining
538 = mod->value_size - (data_size - mod->name_size);
539 mod->value_size = htonl (mod->value_size);
540 mod->name_size = htons (mod->name_size);
541 }
542 else if (0 < data_size)
543 {
544 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got invalid modifier name.\n");
545 notify_ret = GNUNET_SYSERR;
546 }
547 break;
548 }
549 case GNUNET_PSYC_MESSAGE_STATE_MOD_CONT:
550 {
551 msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT);
552 msg->size = sizeof (struct GNUNET_MessageHeader);
553
554 if (NULL != tmit->notify_mod)
555 {
556 max_data_size = GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD;
557 data_size = max_data_size;
558 tmit->in_notify = GNUNET_YES;
559 notify_ret = tmit->notify_mod (tmit->notify_mod_cls,
560 &data_size, &msg[1], NULL, NULL);
561 tmit->in_notify = GNUNET_NO;
562 }
563 tmit->mod_value_remaining -= data_size;
564 LOG (GNUNET_ERROR_TYPE_DEBUG,
565 "transmit_mod (ret: %d, size: %u): %.*s\n",
566 notify_ret, data_size, data_size, &msg[1]);
567 break;
568 }
569 default:
570 GNUNET_assert (0);
571 }
572
573 switch (notify_ret)
574 {
575 case GNUNET_NO:
576 if (0 == data_size)
577 { /* Transmission paused, nothing to send. */
578 tmit->paused = GNUNET_YES;
579 return;
580 }
581 tmit->state
582 = (0 == tmit->mod_value_remaining)
583 ? GNUNET_PSYC_MESSAGE_STATE_MODIFIER
584 : GNUNET_PSYC_MESSAGE_STATE_MOD_CONT;
585 break;
586
587 case GNUNET_YES: /* End of modifiers. */
588 GNUNET_assert (0 == tmit->mod_value_remaining);
589 break;
590
591 default:
592 LOG (GNUNET_ERROR_TYPE_ERROR,
593 "TransmitNotifyModifier callback returned with error.\n");
594
595 tmit->state = GNUNET_PSYC_MESSAGE_STATE_CANCEL;
596 msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL);
597 msg->size = htons (sizeof (*msg));
598 transmit_queue_insert (tmit, msg, GNUNET_YES);
599 tmit->in_transmit = GNUNET_NO;
600 return;
601 }
602
603 if (0 < data_size)
604 {
605 GNUNET_assert (data_size <= max_data_size);
606 msg->size = htons (msg->size + data_size);
607 transmit_queue_insert (tmit, msg, GNUNET_NO);
608 }
609
610 if (GNUNET_YES == notify_ret)
611 {
612 tmit->state = GNUNET_PSYC_MESSAGE_STATE_DATA;
613 if (0 == tmit->acks_pending)
614 transmit_data (tmit);
615 }
616 else
617 {
618 transmit_mod (tmit);
619 }
620}
621
622
623int
624transmit_notify_env (void *cls, uint16_t *data_size, void *data, uint8_t *oper,
625 uint32_t *full_value_size)
626
627{
628 struct GNUNET_PSYC_TransmitHandle *tmit = cls;
629 uint16_t name_size = 0;
630 uint32_t value_size = 0;
631 const char *value = NULL;
632
633 if (NULL != oper)
634 { /* New modifier */
635 if (NULL != tmit->mod)
636 tmit->mod = tmit->mod->next;
637 if (NULL == tmit->mod)
638 { /* No more modifiers, continue with data */
639 *data_size = 0;
640 return GNUNET_YES;
641 }
642
643 GNUNET_assert (tmit->mod->value_size < UINT32_MAX);
644 *full_value_size = tmit->mod->value_size;
645 *oper = tmit->mod->oper;
646 name_size = strlen (tmit->mod->name) + 1;
647
648 if (name_size + tmit->mod->value_size <= *data_size)
649 {
650 value_size = tmit->mod->value_size;
651 *data_size = name_size + value_size;
652 }
653 else /* full modifier does not fit in data, continuation needed */
654 {
655 value_size = *data_size - name_size;
656 tmit->mod_value = tmit->mod->value + value_size;
657 }
658
659 GNUNET_memcpy (data, tmit->mod->name, name_size);
660 GNUNET_memcpy ((char *)data + name_size, tmit->mod->value, value_size);
661 return GNUNET_NO;
662 }
663 else
664 { /* Modifier continuation */
665 GNUNET_assert (NULL != tmit->mod_value && 0 < tmit->mod_value_remaining);
666 value = tmit->mod_value;
667 if (tmit->mod_value_remaining <= *data_size)
668 {
669 value_size = tmit->mod_value_remaining;
670 tmit->mod_value = NULL;
671 }
672 else
673 {
674 value_size = *data_size;
675 tmit->mod_value += value_size;
676 }
677
678 if (*data_size < value_size)
679 {
680 LOG (GNUNET_ERROR_TYPE_DEBUG,
681 "Value in environment larger than buffer: %u < %zu\n",
682 *data_size, value_size);
683 *data_size = 0;
684 return GNUNET_NO;
685 }
686
687 *data_size = value_size;
688 GNUNET_memcpy (data, value, value_size);
689 return (NULL == tmit->mod_value) ? GNUNET_YES : GNUNET_NO;
690 }
691}
692
693
694/**
695 * Transmit a message.
696 *
697 * @param tmit
698 * Transmission handle.
699 * @param method_name
700 * Which method should be invoked.
701 * @param env
702 * Environment for the message.
703 * Should stay available until the first call to notify_data.
704 * Can be NULL if there are no modifiers or @a notify_mod is
705 * provided instead.
706 * @param notify_mod
707 * Function to call to obtain modifiers.
708 * Can be NULL if there are no modifiers or @a env is provided instead.
709 * @param notify_data
710 * Function to call to obtain fragments of the data.
711 * @param notify_cls
712 * Closure for @a notify_mod and @a notify_data.
713 * @param flags
714 * Flags for the message being transmitted.
715 *
716 * @return #GNUNET_OK if the transmission was started.
717 * #GNUNET_SYSERR if another transmission is already going on.
718 */
719int
720GNUNET_PSYC_transmit_message (struct GNUNET_PSYC_TransmitHandle *tmit,
721 const char *method_name,
722 const struct GNUNET_PSYC_Environment *env,
723 GNUNET_PSYC_TransmitNotifyModifier notify_mod,
724 GNUNET_PSYC_TransmitNotifyData notify_data,
725 void *notify_cls,
726 uint32_t flags)
727{
728 if (GNUNET_NO != tmit->in_transmit)
729 return GNUNET_SYSERR;
730 tmit->in_transmit = GNUNET_YES;
731
732 size_t size = strlen (method_name) + 1;
733 struct GNUNET_PSYC_MessageMethod *pmeth;
734
735 tmit->env = GNUNET_MQ_msg_extra (tmit->msg,
736 GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD,
737 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE);
738 /* store current message size in host byte order
739 * then later switch it to network byte order before sending */
740 tmit->msg->size = sizeof (*tmit->msg) + sizeof (*pmeth) + size;
741
742 if (NULL != notify_mod)
743 {
744 tmit->notify_mod = notify_mod;
745 tmit->notify_mod_cls = notify_cls;
746 }
747 else
748 {
749 tmit->notify_mod = &transmit_notify_env;
750 tmit->notify_mod_cls = tmit;
751 if (NULL != env)
752 {
753 struct GNUNET_PSYC_Modifier mod = {};
754 mod.next = GNUNET_PSYC_env_head (env);
755 tmit->mod = &mod;
756
757 struct GNUNET_PSYC_Modifier *m = tmit->mod;
758 while (NULL != (m = m->next))
759 {
760 if (m->oper != GNUNET_PSYC_OP_SET)
761 flags |= GNUNET_PSYC_MASTER_TRANSMIT_STATE_MODIFY;
762 }
763 }
764 else
765 {
766 tmit->mod = NULL;
767 }
768 }
769
770 pmeth = (struct GNUNET_PSYC_MessageMethod *) &tmit->msg[1];
771 pmeth->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD);
772 pmeth->header.size = htons (sizeof (*pmeth) + size);
773 pmeth->flags = htonl (flags);
774 GNUNET_memcpy (&pmeth[1], method_name, size);
775
776 tmit->state = GNUNET_PSYC_MESSAGE_STATE_MODIFIER;
777 tmit->notify_data = notify_data;
778 tmit->notify_data_cls = notify_cls;
779
780 transmit_mod (tmit);
781 return GNUNET_OK;
782}
783
784
785/**
786 * Resume transmission.
787 *
788 * @param tmit Transmission handle.
789 */
790void
791GNUNET_PSYC_transmit_resume (struct GNUNET_PSYC_TransmitHandle *tmit)
792{
793 if (GNUNET_YES != tmit->in_transmit || GNUNET_NO != tmit->in_notify)
794 return;
795
796 if (0 == tmit->acks_pending)
797 {
798 tmit->paused = GNUNET_NO;
799 transmit_data (tmit);
800 }
801}
802
803
804/**
805 * Abort transmission request.
806 *
807 * @param tmit Transmission handle.
808 */
809void
810GNUNET_PSYC_transmit_cancel (struct GNUNET_PSYC_TransmitHandle *tmit)
811{
812 if (GNUNET_NO == tmit->in_transmit)
813 return;
814
815 tmit->state = GNUNET_PSYC_MESSAGE_STATE_CANCEL;
816 tmit->in_transmit = GNUNET_NO;
817 tmit->paused = GNUNET_NO;
818
819 /* FIXME */
820 struct GNUNET_MessageHeader msg;
821 msg.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL);
822 msg.size = htons (sizeof (msg));
823 transmit_queue_insert (tmit, &msg, GNUNET_YES);
824}
825
826
827/**
828 * Got acknowledgement of a transmitted message part, continue transmission.
829 *
830 * @param tmit Transmission handle.
831 */
832void
833GNUNET_PSYC_transmit_got_ack (struct GNUNET_PSYC_TransmitHandle *tmit)
834{
835 if (0 == tmit->acks_pending)
836 {
837 LOG (GNUNET_ERROR_TYPE_WARNING, "Ignoring extraneous message ACK\n");
838 GNUNET_break (0);
839 return;
840 }
841 tmit->acks_pending--;
842
843 if (GNUNET_YES == tmit->paused)
844 return;
845
846 switch (tmit->state)
847 {
848 case GNUNET_PSYC_MESSAGE_STATE_MODIFIER:
849 case GNUNET_PSYC_MESSAGE_STATE_MOD_CONT:
850 transmit_mod (tmit);
851 break;
852
853 case GNUNET_PSYC_MESSAGE_STATE_DATA:
854 transmit_data (tmit);
855 break;
856
857 case GNUNET_PSYC_MESSAGE_STATE_END:
858 case GNUNET_PSYC_MESSAGE_STATE_CANCEL:
859 break;
860
861 default:
862 LOG (GNUNET_ERROR_TYPE_DEBUG,
863 "Ignoring message ACK in state %u.\n", tmit->state);
864 }
865}
866
867
868/**** Receiving messages ****/
869
870
871/**
872 * Create handle for receiving messages.
873 */
874struct GNUNET_PSYC_ReceiveHandle *
875GNUNET_PSYC_receive_create (GNUNET_PSYC_MessageCallback message_cb,
876 GNUNET_PSYC_MessagePartCallback message_part_cb,
877 void *cb_cls)
878{
879 struct GNUNET_PSYC_ReceiveHandle *recv = GNUNET_malloc (sizeof (*recv));
880 recv->message_cb = message_cb;
881 recv->message_part_cb = message_part_cb;
882 recv->cb_cls = cb_cls;
883 return recv;
884}
885
886
887/**
888 * Destroy handle for receiving messages.
889 */
890void
891GNUNET_PSYC_receive_destroy (struct GNUNET_PSYC_ReceiveHandle *recv)
892{
893 GNUNET_free (recv);
894}
895
896
897/**
898 * Reset stored data related to the last received message.
899 */
900void
901GNUNET_PSYC_receive_reset (struct GNUNET_PSYC_ReceiveHandle *recv)
902{
903 recv->state = GNUNET_PSYC_MESSAGE_STATE_START;
904 recv->flags = 0;
905 recv->message_id = 0;
906 recv->mod_value_size = 0;
907 recv->mod_value_size_expected = 0;
908}
909
910
911static void
912recv_error (struct GNUNET_PSYC_ReceiveHandle *recv)
913{
914 if (NULL != recv->message_part_cb)
915 recv->message_part_cb (recv->cb_cls, NULL, NULL);
916
917 if (NULL != recv->message_cb)
918 recv->message_cb (recv->cb_cls, NULL);
919
920 GNUNET_PSYC_receive_reset (recv);
921}
922
923
924/**
925 * Handle incoming PSYC message.
926 *
927 * @param recv Receive handle.
928 * @param msg The message.
929 *
930 * @return #GNUNET_OK on success,
931 * #GNUNET_SYSERR on receive error.
932 */
933int
934GNUNET_PSYC_receive_message (struct GNUNET_PSYC_ReceiveHandle *recv,
935 const struct GNUNET_PSYC_MessageHeader *msg)
936{
937 uint16_t size = ntohs (msg->header.size);
938 uint32_t flags = ntohl (msg->flags);
939
940 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG,
941 (struct GNUNET_MessageHeader *) msg);
942
943 if (GNUNET_PSYC_MESSAGE_STATE_START == recv->state)
944 {
945 recv->message_id = GNUNET_ntohll (msg->message_id);
946 recv->flags = flags;
947 recv->slave_pub_key = msg->slave_pub_key;
948 recv->mod_value_size = 0;
949 recv->mod_value_size_expected = 0;
950 }
951 else if (GNUNET_ntohll (msg->message_id) != recv->message_id)
952 {
953 // FIXME
954 LOG (GNUNET_ERROR_TYPE_WARNING,
955 "Unexpected message ID. Got: %" PRIu64 ", expected: %" PRIu64 "\n",
956 GNUNET_ntohll (msg->message_id), recv->message_id);
957 GNUNET_break_op (0);
958 recv_error (recv);
959 return GNUNET_SYSERR;
960 }
961 else if (flags != recv->flags)
962 {
963 LOG (GNUNET_ERROR_TYPE_WARNING,
964 "Unexpected message flags. Got: %lu, expected: %lu\n",
965 flags, recv->flags);
966 GNUNET_break_op (0);
967 recv_error (recv);
968 return GNUNET_SYSERR;
969 }
970
971 uint16_t pos = 0, psize = 0, ptype, size_eq, size_min;
972
973 for (pos = 0; sizeof (*msg) + pos < size; pos += psize)
974 {
975 const struct GNUNET_MessageHeader *pmsg
976 = (const struct GNUNET_MessageHeader *) ((char *) &msg[1] + pos);
977 psize = ntohs (pmsg->size);
978 ptype = ntohs (pmsg->type);
979 size_eq = size_min = 0;
980
981 if (psize < sizeof (*pmsg) || sizeof (*msg) + pos + psize > size)
982 {
983 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
984 "Dropping message of type %u with invalid size %u.\n",
985 ptype, psize);
986 recv_error (recv);
987 return GNUNET_SYSERR;
988 }
989
990 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
991 "Received message part of type %u and size %u from PSYC.\n",
992 ptype, psize);
993 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
994
995 switch (ptype)
996 {
997 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
998 size_min = sizeof (struct GNUNET_PSYC_MessageMethod);
999 break;
1000 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
1001 size_min = sizeof (struct GNUNET_PSYC_MessageModifier);
1002 break;
1003 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
1004 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
1005 size_min = sizeof (struct GNUNET_MessageHeader);
1006 break;
1007 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1008 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
1009 size_eq = sizeof (struct GNUNET_MessageHeader);
1010 break;
1011 default:
1012 GNUNET_break_op (0);
1013 recv_error (recv);
1014 return GNUNET_SYSERR;
1015 }
1016
1017 if (! ((0 < size_eq && psize == size_eq)
1018 || (0 < size_min && size_min <= psize)))
1019 {
1020 GNUNET_break_op (0);
1021 recv_error (recv);
1022 return GNUNET_SYSERR;
1023 }
1024
1025 switch (ptype)
1026 {
1027 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
1028 {
1029 struct GNUNET_PSYC_MessageMethod *meth
1030 = (struct GNUNET_PSYC_MessageMethod *) pmsg;
1031
1032 if (GNUNET_PSYC_MESSAGE_STATE_START != recv->state)
1033 {
1034 LOG (GNUNET_ERROR_TYPE_WARNING,
1035 "Dropping out of order message method (%u).\n",
1036 recv->state);
1037 /* It is normal to receive an incomplete message right after connecting,
1038 * but should not happen later.
1039 * FIXME: add a check for this condition.
1040 */
1041 GNUNET_break_op (0);
1042 recv_error (recv);
1043 return GNUNET_SYSERR;
1044 }
1045
1046 if ('\0' != *((char *) meth + psize - 1))
1047 {
1048 LOG (GNUNET_ERROR_TYPE_WARNING,
1049 "Dropping message with malformed method. "
1050 "Message ID: %" PRIu64 "\n", recv->message_id);
1051 GNUNET_break_op (0);
1052 recv_error (recv);
1053 return GNUNET_SYSERR;
1054 }
1055 recv->state = GNUNET_PSYC_MESSAGE_STATE_METHOD;
1056 break;
1057 }
1058 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
1059 {
1060 if (!(GNUNET_PSYC_MESSAGE_STATE_METHOD == recv->state
1061 || GNUNET_PSYC_MESSAGE_STATE_MODIFIER == recv->state
1062 || GNUNET_PSYC_MESSAGE_STATE_MOD_CONT == recv->state))
1063 {
1064 LOG (GNUNET_ERROR_TYPE_WARNING,
1065 "Dropping out of order message modifier (%u).\n",
1066 recv->state);
1067 GNUNET_break_op (0);
1068 recv_error (recv);
1069 return GNUNET_SYSERR;
1070 }
1071
1072 struct GNUNET_PSYC_MessageModifier *mod
1073 = (struct GNUNET_PSYC_MessageModifier *) pmsg;
1074
1075 uint16_t name_size = ntohs (mod->name_size);
1076 recv->mod_value_size_expected = ntohl (mod->value_size);
1077 recv->mod_value_size = psize - sizeof (*mod) - name_size;
1078
1079 if (psize < sizeof (*mod) + name_size
1080 || '\0' != *((char *) &mod[1] + name_size - 1)
1081 || recv->mod_value_size_expected < recv->mod_value_size)
1082 {
1083 LOG (GNUNET_ERROR_TYPE_WARNING, "Dropping malformed modifier.\n");
1084 GNUNET_break_op (0);
1085 recv_error (recv);
1086 return GNUNET_SYSERR;
1087 }
1088 recv->state = GNUNET_PSYC_MESSAGE_STATE_MODIFIER;
1089 break;
1090 }
1091 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
1092 {
1093 recv->mod_value_size += psize - sizeof (*pmsg);
1094
1095 if (!(GNUNET_PSYC_MESSAGE_STATE_MODIFIER == recv->state
1096 || GNUNET_PSYC_MESSAGE_STATE_MOD_CONT == recv->state)
1097 || recv->mod_value_size_expected < recv->mod_value_size)
1098 {
1099 LOG (GNUNET_ERROR_TYPE_WARNING,
1100 "Dropping out of order message modifier continuation "
1101 "!(%u == %u || %u == %u) || %lu < %lu.\n",
1102 GNUNET_PSYC_MESSAGE_STATE_MODIFIER, recv->state,
1103 GNUNET_PSYC_MESSAGE_STATE_MOD_CONT, recv->state,
1104 recv->mod_value_size_expected, recv->mod_value_size);
1105 GNUNET_break_op (0);
1106 recv_error (recv);
1107 return GNUNET_SYSERR;
1108 }
1109 break;
1110 }
1111 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
1112 {
1113 if (recv->state < GNUNET_PSYC_MESSAGE_STATE_METHOD
1114 || recv->mod_value_size_expected != recv->mod_value_size)
1115 {
1116 LOG (GNUNET_ERROR_TYPE_WARNING,
1117 "Dropping out of order message data fragment "
1118 "(%u < %u || %lu != %lu).\n",
1119 recv->state, GNUNET_PSYC_MESSAGE_STATE_METHOD,
1120 recv->mod_value_size_expected, recv->mod_value_size);
1121
1122 GNUNET_break_op (0);
1123 recv_error (recv);
1124 return GNUNET_SYSERR;
1125 }
1126 recv->state = GNUNET_PSYC_MESSAGE_STATE_DATA;
1127 break;
1128 }
1129 }
1130
1131 if (NULL != recv->message_part_cb)
1132 recv->message_part_cb (recv->cb_cls, msg, pmsg);
1133
1134 switch (ptype)
1135 {
1136 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1137 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
1138 GNUNET_PSYC_receive_reset (recv);
1139 break;
1140 }
1141 }
1142
1143 if (NULL != recv->message_cb)
1144 recv->message_cb (recv->cb_cls, msg);
1145 return GNUNET_OK;
1146}
1147
1148
1149/**
1150 * Check if @a data contains a series of valid message parts.
1151 *
1152 * @param data_size Size of @a data.
1153 * @param data Data.
1154 * @param[out] first_ptype Type of first message part.
1155 * @param[out] last_ptype Type of last message part.
1156 *
1157 * @return Number of message parts found in @a data.
1158 * or GNUNET_SYSERR if the message contains invalid parts.
1159 */
1160int
1161GNUNET_PSYC_receive_check_parts (uint16_t data_size, const char *data,
1162 uint16_t *first_ptype, uint16_t *last_ptype)
1163{
1164 const struct GNUNET_MessageHeader *pmsg;
1165 uint16_t parts = 0, ptype = 0, psize = 0, pos = 0;
1166 if (NULL != first_ptype)
1167 *first_ptype = 0;
1168 if (NULL != last_ptype)
1169 *last_ptype = 0;
1170
1171 for (pos = 0; pos < data_size; pos += psize, parts++)
1172 {
1173 pmsg = (const struct GNUNET_MessageHeader *) (data + pos);
1174 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
1175 psize = ntohs (pmsg->size);
1176 ptype = ntohs (pmsg->type);
1177 if (0 == parts && NULL != first_ptype)
1178 *first_ptype = ptype;
1179 if (NULL != last_ptype
1180 && *last_ptype < GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END)
1181 *last_ptype = ptype;
1182 if (psize < sizeof (*pmsg)
1183 || pos + psize > data_size
1184 || ptype < GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD
1185 || GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL < ptype)
1186 {
1187 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1188 "Invalid message part of type %u and size %u.\n",
1189 ptype, psize);
1190 return GNUNET_SYSERR;
1191 }
1192 /** @todo FIXME: check message part order */
1193 }
1194 return parts;
1195}
1196
1197
1198struct ParseMessageClosure
1199{
1200 struct GNUNET_PSYC_Environment *env;
1201 const char **method_name;
1202 const void **data;
1203 uint16_t *data_size;
1204 enum GNUNET_PSYC_MessageState msg_state;
1205};
1206
1207
1208static void
1209parse_message_part_cb (void *cls,
1210 const struct GNUNET_PSYC_MessageHeader *msg,
1211 const struct GNUNET_MessageHeader *pmsg)
1212{
1213 struct ParseMessageClosure *pmc = cls;
1214 if (NULL == pmsg)
1215 {
1216 pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_ERROR;
1217 return;
1218 }
1219
1220 switch (ntohs (pmsg->type))
1221 {
1222 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
1223 {
1224 struct GNUNET_PSYC_MessageMethod *
1225 pmeth = (struct GNUNET_PSYC_MessageMethod *) pmsg;
1226 *pmc->method_name = (const char *) &pmeth[1];
1227 pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_METHOD;
1228 break;
1229 }
1230
1231 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
1232 {
1233 struct GNUNET_PSYC_MessageModifier *
1234 pmod = (struct GNUNET_PSYC_MessageModifier *) pmsg;
1235
1236 const char *name = (const char *) &pmod[1];
1237 const void *value = name + ntohs (pmod->name_size);
1238 GNUNET_PSYC_env_add (pmc->env, pmod->oper, name, value,
1239 ntohl (pmod->value_size));
1240 pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_MODIFIER;
1241 break;
1242 }
1243
1244 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
1245 *pmc->data = &pmsg[1];
1246 *pmc->data_size = ntohs (pmsg->size) - sizeof (*pmsg);
1247 pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_DATA;
1248 break;
1249
1250 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1251 pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_END;
1252 break;
1253
1254 default:
1255 pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_ERROR;
1256 }
1257}
1258
1259
1260/**
1261 * Parse PSYC message.
1262 *
1263 * @param msg
1264 * The PSYC message to parse.
1265 * @param[out] method_name
1266 * Pointer to the method name inside @a pmsg.
1267 * @param env
1268 * The environment for the message with a list of modifiers.
1269 * @param[out] data
1270 * Pointer to data inside @a msg.
1271 * @param[out] data_size
1272 * Size of @data is written here.
1273 *
1274 * @return #GNUNET_OK on success,
1275 * #GNUNET_SYSERR on parse error.
1276 */
1277int
1278GNUNET_PSYC_message_parse (const struct GNUNET_PSYC_MessageHeader *msg,
1279 const char **method_name,
1280 struct GNUNET_PSYC_Environment *env,
1281 const void **data,
1282 uint16_t *data_size)
1283{
1284 struct ParseMessageClosure cls;
1285 cls.env = env;
1286 cls.method_name = method_name;
1287 cls.data = data;
1288 cls.data_size = data_size;
1289
1290 struct GNUNET_PSYC_ReceiveHandle *
1291 recv = GNUNET_PSYC_receive_create (NULL, parse_message_part_cb, &cls);
1292 int ret = GNUNET_PSYC_receive_message (recv, msg);
1293 GNUNET_PSYC_receive_destroy (recv);
1294
1295 if (GNUNET_OK != ret)
1296 return GNUNET_SYSERR;
1297
1298 return (GNUNET_PSYC_MESSAGE_STATE_END == cls.msg_state)
1299 ? GNUNET_OK
1300 : GNUNET_NO;
1301}
1302
1303
1304/**
1305 * Initialize PSYC message header.
1306 */
1307void
1308GNUNET_PSYC_message_header_init (struct GNUNET_PSYC_MessageHeader *pmsg,
1309 const struct GNUNET_MULTICAST_MessageHeader *mmsg,
1310 uint32_t flags)
1311{
1312 uint16_t size = ntohs (mmsg->header.size);
1313 uint16_t psize = sizeof (*pmsg) + size - sizeof (*mmsg);
1314
1315 pmsg->header.size = htons (psize);
1316 pmsg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE);
1317 pmsg->message_id = mmsg->message_id;
1318 pmsg->fragment_offset = mmsg->fragment_offset;
1319 pmsg->flags = htonl (flags);
1320
1321 GNUNET_memcpy (&pmsg[1], &mmsg[1], size - sizeof (*mmsg));
1322}
1323
1324
1325/**
1326 * Create a new PSYC message header from a multicast message.
1327 */
1328struct GNUNET_PSYC_MessageHeader *
1329GNUNET_PSYC_message_header_create (const struct GNUNET_MULTICAST_MessageHeader *mmsg,
1330 uint32_t flags)
1331{
1332 struct GNUNET_PSYC_MessageHeader *pmsg;
1333 uint16_t size = ntohs (mmsg->header.size);
1334 uint16_t psize = sizeof (*pmsg) + size - sizeof (*mmsg);
1335
1336 pmsg = GNUNET_malloc (psize);
1337 GNUNET_PSYC_message_header_init (pmsg, mmsg, flags);
1338 return pmsg;
1339}
1340
1341
1342/**
1343 * Create a new PSYC message header from a PSYC message.
1344 */
1345struct GNUNET_PSYC_MessageHeader *
1346GNUNET_PSYC_message_header_create_from_psyc (const struct GNUNET_PSYC_Message *msg)
1347{
1348 uint16_t msg_size = ntohs (msg->header.size);
1349 struct GNUNET_PSYC_MessageHeader *
1350 pmsg = GNUNET_malloc (sizeof (*pmsg) + msg_size - sizeof (*msg));
1351 pmsg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE);
1352 pmsg->header.size = htons (sizeof (*pmsg) + msg_size - sizeof (*msg));
1353 GNUNET_memcpy (&pmsg[1], &msg[1], msg_size - sizeof (*msg));
1354 return pmsg;
1355}
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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @author Gabor X Toth
23 *
24 * @file
25 * PSYC Slicer API
26 */
27
28#include <inttypes.h>
29
30#include "platform.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_psyc_util_lib.h"
33
34#define LOG(kind,...) GNUNET_log_from (kind, "psyc-util-slicer",__VA_ARGS__)
35
36
37/**
38 * Handle for a try-and-slice instance.
39 */
40struct GNUNET_PSYC_Slicer
41{
42 /**
43 * Method handlers: H(method_name) -> SlicerMethodCallbacks
44 */
45 struct GNUNET_CONTAINER_MultiHashMap *method_handlers;
46
47 /**
48 * Modifier handlers: H(modifier_name) -> SlicerModifierCallbacks
49 */
50 struct GNUNET_CONTAINER_MultiHashMap *modifier_handlers;
51
52 /**
53 * Receive handle for incoming messages.
54 */
55 struct GNUNET_PSYC_ReceiveHandle *recv;
56
57 /**
58 * Currently being processed message.
59 */
60 const struct GNUNET_PSYC_MessageHeader *msg;
61
62 /**
63 * Currently being processed message part.
64 */
65 const struct GNUNET_MessageHeader *pmsg;
66
67 /**
68 * ID of currently being received message.
69 */
70 uint64_t message_id;
71
72 /**
73 * Fragment offset of currently being received message.
74 */
75 uint64_t fragment_offset;
76
77 /**
78 * Flags of currently being received message.
79 */
80 uint32_t flags;
81
82 /**
83 * Method name of currently being received message.
84 */
85 char *method_name;
86
87 /**
88 * Name of currently processed modifier.
89 */
90 char *mod_name;
91
92 /**
93 * Value of currently processed modifier.
94 */
95 char *mod_value;
96
97 /**
98 * Public key of the nym the current message originates from.
99 */
100 struct GNUNET_CRYPTO_EcdsaPublicKey nym_pub_key;
101
102 /**
103 * Size of @a method_name (including terminating \0).
104 */
105 uint16_t method_name_size;
106
107 /**
108 * Size of @a modifier_name (including terminating \0).
109 */
110 uint16_t mod_name_size;
111
112 /**
113 * Size of modifier value fragment.
114 */
115 uint16_t mod_value_size;
116
117 /**
118 * Full size of modifier value.
119 */
120 uint16_t mod_full_value_size;
121
122 /**
123 * Remaining bytes from the value of the current modifier.
124 */
125 uint16_t mod_value_remaining;
126
127 /**
128 * Operator of currently processed modifier.
129 */
130 uint8_t mod_oper;
131};
132
133
134/**
135 * Callbacks for a slicer method handler.
136 */
137struct SlicerMethodCallbacks
138{
139 GNUNET_PSYC_MessageCallback msg_cb;
140 GNUNET_PSYC_MethodCallback method_cb;
141 GNUNET_PSYC_ModifierCallback modifier_cb;
142 GNUNET_PSYC_DataCallback data_cb;
143 GNUNET_PSYC_EndOfMessageCallback eom_cb;
144 void *cls;
145};
146
147
148struct SlicerMethodRemoveClosure
149{
150 struct GNUNET_PSYC_Slicer *slicer;
151 struct SlicerMethodCallbacks rm_cbs;
152};
153
154
155/**
156 * Callbacks for a slicer method handler.
157 */
158struct SlicerModifierCallbacks
159{
160 GNUNET_PSYC_ModifierCallback modifier_cb;
161 void *cls;
162};
163
164
165struct SlicerModifierRemoveClosure
166{
167 struct GNUNET_PSYC_Slicer *slicer;
168 struct SlicerModifierCallbacks rm_cbs;
169};
170
171
172/**
173 * Call a method handler for an incoming message part.
174 */
175static int
176slicer_method_handler_notify (void *cls, const struct GNUNET_HashCode *key,
177 void *value)
178{
179 struct GNUNET_PSYC_Slicer *slicer = cls;
180 const struct GNUNET_MessageHeader *pmsg = slicer->pmsg;
181 struct SlicerMethodCallbacks *cbs = value;
182
183 uint16_t ptype = ntohs (pmsg->type);
184 switch (ptype)
185 {
186 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
187 {
188 if (NULL != cbs->msg_cb)
189 cbs->msg_cb (cbs->cls, slicer->msg);
190 if (NULL == cbs->method_cb)
191 break;
192 struct GNUNET_PSYC_MessageMethod *
193 meth = (struct GNUNET_PSYC_MessageMethod *) pmsg;
194 cbs->method_cb (cbs->cls, slicer->msg, meth, slicer->message_id,
195 slicer->method_name);
196 break;
197 }
198
199 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
200 {
201 if (NULL == cbs->modifier_cb)
202 break;
203 struct GNUNET_PSYC_MessageModifier *
204 mod = (struct GNUNET_PSYC_MessageModifier *) pmsg;
205 cbs->modifier_cb (cbs->cls, slicer->msg, &mod->header, slicer->message_id,
206 mod->oper, (const char *) &mod[1],
207 (const void *) &mod[1] + ntohs (mod->name_size),
208 ntohs (mod->header.size) - sizeof (*mod) - ntohs (mod->name_size),
209 ntohs (mod->value_size));
210 break;
211 }
212
213 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
214 {
215 if (NULL == cbs->modifier_cb)
216 break;
217 cbs->modifier_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id,
218 slicer->mod_oper, slicer->mod_name, &pmsg[1],
219 ntohs (pmsg->size) - sizeof (*pmsg),
220 slicer->mod_full_value_size);
221 break;
222 }
223
224 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
225 {
226 if (NULL == cbs->data_cb)
227 break;
228 cbs->data_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id,
229 &pmsg[1], ntohs (pmsg->size) - sizeof (*pmsg));
230 break;
231 }
232
233 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
234 if (NULL == cbs->eom_cb)
235 break;
236 cbs->eom_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id, GNUNET_NO);
237 break;
238
239 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
240 if (NULL == cbs->eom_cb)
241 break;
242 cbs->eom_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id, GNUNET_YES);
243 break;
244 }
245 return GNUNET_YES;
246}
247
248
249/**
250 * Call a method handler for an incoming message part.
251 */
252static int
253slicer_modifier_handler_notify (void *cls, const struct GNUNET_HashCode *key,
254 void *value)
255{
256 struct GNUNET_PSYC_Slicer *slicer = cls;
257 struct SlicerModifierCallbacks *cbs = value;
258
259 cbs->modifier_cb (cbs->cls, slicer->msg, slicer->pmsg, slicer->message_id,
260 slicer->mod_oper, slicer->mod_name, slicer->mod_value,
261 slicer->mod_value_size, slicer->mod_full_value_size);
262 return GNUNET_YES;
263}
264
265
266/**
267 * Process an incoming message and call matching handlers.
268 *
269 * @param slicer
270 * The slicer to use.
271 * @param msg
272 * The message as it arrived from the network.
273 */
274void
275GNUNET_PSYC_slicer_message (struct GNUNET_PSYC_Slicer *slicer,
276 const struct GNUNET_PSYC_MessageHeader *msg)
277{
278 GNUNET_PSYC_receive_message (slicer->recv, msg);
279}
280
281
282/**
283 * Process an incoming message part and call matching handlers.
284 *
285 * @param cls
286 * Closure.
287 * @param message_id
288 * ID of the message.
289 * @param flags
290 * Flags for the message.
291 * @see enum GNUNET_PSYC_MessageFlags
292 * @param msg
293 * The message part. as it arrived from the network.
294 */
295void
296GNUNET_PSYC_slicer_message_part (struct GNUNET_PSYC_Slicer *slicer,
297 const struct GNUNET_PSYC_MessageHeader *msg,
298 const struct GNUNET_MessageHeader *pmsg)
299{
300 slicer->msg = msg;
301 slicer->pmsg = pmsg;
302
303 uint64_t message_id = GNUNET_ntohll (msg->message_id);
304
305 uint16_t ptype = ntohs (pmsg->type);
306 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == ptype)
307 {
308 struct GNUNET_PSYC_MessageMethod *
309 meth = (struct GNUNET_PSYC_MessageMethod *) pmsg;
310 slicer->method_name_size = ntohs (meth->header.size) - sizeof (*meth);
311 slicer->method_name = GNUNET_malloc (slicer->method_name_size);
312 GNUNET_memcpy (slicer->method_name, &meth[1], slicer->method_name_size);
313 slicer->message_id = message_id;
314 }
315 else
316 {
317 GNUNET_assert (message_id == slicer->message_id);
318 }
319
320 char *nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&msg->slave_pub_key);
321 LOG (GNUNET_ERROR_TYPE_DEBUG,
322 "Slicer received message of type %u and size %u, "
323 "with ID %" PRIu64 " and method %s from %s\n",
324 ptype, ntohs (pmsg->size), message_id, slicer->method_name, nym_str);
325 GNUNET_free (nym_str);
326
327 /* try-and-slice modifier */
328
329 switch (ptype)
330 {
331 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
332 {
333 struct GNUNET_PSYC_MessageModifier *
334 mod = (struct GNUNET_PSYC_MessageModifier *) pmsg;
335 slicer->mod_oper = mod->oper;
336 slicer->mod_name_size = ntohs (mod->name_size);
337 slicer->mod_name = GNUNET_malloc (slicer->mod_name_size);
338 GNUNET_memcpy (slicer->mod_name, &mod[1], slicer->mod_name_size);
339 slicer->mod_value = (char *) &mod[1] + slicer->mod_name_size;
340 slicer->mod_full_value_size = ntohs (mod->value_size);
341 slicer->mod_value_remaining = slicer->mod_full_value_size;
342 slicer->mod_value_size
343 = ntohs (mod->header.size) - sizeof (*mod) - slicer->mod_name_size;
344 // fall through
345 }
346 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
347 if (ptype == GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT)
348 {
349 slicer->mod_value = (char *) &pmsg[1];
350 slicer->mod_value_size = ntohs (pmsg->size) - sizeof (*pmsg);
351 }
352 slicer->mod_value_remaining -= slicer->mod_value_size;
353 char *name = GNUNET_malloc (slicer->mod_name_size);
354 GNUNET_memcpy (name, slicer->mod_name, slicer->mod_name_size);
355 do
356 {
357 struct GNUNET_HashCode key;
358 uint16_t name_len = strlen (name);
359 GNUNET_CRYPTO_hash (name, name_len, &key);
360 GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key,
361 slicer_modifier_handler_notify,
362 slicer);
363 char *p = strrchr (name, '_');
364 if (NULL == p)
365 break;
366 *p = '\0';
367 } while (1);
368 GNUNET_free (name);
369 }
370
371 /* try-and-slice method */
372
373 char *name = GNUNET_malloc (slicer->method_name_size);
374 GNUNET_memcpy (name, slicer->method_name, slicer->method_name_size);
375 do
376 {
377 struct GNUNET_HashCode key;
378 uint16_t name_len = strlen (name);
379 GNUNET_CRYPTO_hash (name, name_len, &key);
380 GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key,
381 slicer_method_handler_notify,
382 slicer);
383 char *p = strrchr (name, '_');
384 if (NULL == p)
385 break;
386 *p = '\0';
387 } while (1);
388 GNUNET_free (name);
389
390 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
391 GNUNET_free (slicer->method_name);
392
393 if (0 == slicer->mod_value_remaining && NULL != slicer->mod_name)
394 {
395 GNUNET_free (slicer->mod_name);
396 slicer->mod_name = NULL;
397 slicer->mod_name_size = 0;
398 slicer->mod_value_size = 0;
399 slicer->mod_full_value_size = 0;
400 slicer->mod_oper = 0;
401 }
402
403 slicer->msg = NULL;
404 slicer->pmsg = NULL;
405}
406
407
408/**
409 * Create a try-and-slice instance.
410 *
411 * A slicer processes incoming messages and notifies callbacks about matching
412 * methods or modifiers encountered.
413 *
414 * @return A new try-and-slice construct.
415 */
416struct GNUNET_PSYC_Slicer *
417GNUNET_PSYC_slicer_create (void)
418{
419 struct GNUNET_PSYC_Slicer *slicer = GNUNET_malloc (sizeof (*slicer));
420 slicer->method_handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
421 slicer->modifier_handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
422 slicer->recv = GNUNET_PSYC_receive_create (NULL,
423 (GNUNET_PSYC_MessagePartCallback)
424 GNUNET_PSYC_slicer_message_part,
425 slicer);
426 return slicer;
427}
428
429
430/**
431 * Add a method to the try-and-slice instance.
432 *
433 * The callbacks are called for messages with a matching @a method_name prefix.
434 *
435 * @param slicer
436 * The try-and-slice instance to extend.
437 * @param method_name
438 * Name of the given method, use empty string to match all.
439 * @param method_cb
440 * Method handler invoked upon a matching message.
441 * @param modifier_cb
442 * Modifier handler, invoked after @a method_cb
443 * for each modifier in the message.
444 * @param data_cb
445 * Data handler, invoked after @a modifier_cb for each data fragment.
446 * @param eom_cb
447 * Invoked upon reaching the end of a matching message.
448 * @param cls
449 * Closure for the callbacks.
450 */
451void
452GNUNET_PSYC_slicer_method_add (struct GNUNET_PSYC_Slicer *slicer,
453 const char *method_name,
454 GNUNET_PSYC_MessageCallback msg_cb,
455 GNUNET_PSYC_MethodCallback method_cb,
456 GNUNET_PSYC_ModifierCallback modifier_cb,
457 GNUNET_PSYC_DataCallback data_cb,
458 GNUNET_PSYC_EndOfMessageCallback eom_cb,
459 void *cls)
460{
461 struct GNUNET_HashCode key;
462 GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key);
463
464 struct SlicerMethodCallbacks *cbs = GNUNET_malloc (sizeof (*cbs));
465 cbs->msg_cb = msg_cb,
466 cbs->method_cb = method_cb;
467 cbs->modifier_cb = modifier_cb;
468 cbs->data_cb = data_cb;
469 cbs->eom_cb = eom_cb;
470 cbs->cls = cls;
471
472 GNUNET_CONTAINER_multihashmap_put (slicer->method_handlers, &key, cbs,
473 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
474}
475
476
477static int
478slicer_method_remove (void *cls, const struct GNUNET_HashCode *key, void *value)
479{
480 struct SlicerMethodRemoveClosure *rm_cls = cls;
481 struct GNUNET_PSYC_Slicer *slicer = rm_cls->slicer;
482 struct SlicerMethodCallbacks *rm_cbs = &rm_cls->rm_cbs;
483 struct SlicerMethodCallbacks *cbs = value;
484
485 if ((NULL == rm_cbs->msg_cb || cbs->msg_cb == rm_cbs->msg_cb)
486 && (NULL == rm_cbs->method_cb || cbs->method_cb == rm_cbs->method_cb)
487 && (NULL == rm_cbs->modifier_cb || cbs->modifier_cb == rm_cbs->modifier_cb)
488 && (NULL == rm_cbs->data_cb || cbs->data_cb == rm_cbs->data_cb)
489 && (NULL == rm_cbs->eom_cb || cbs->eom_cb == rm_cbs->eom_cb))
490 {
491 GNUNET_CONTAINER_multihashmap_remove (slicer->method_handlers, key, cbs);
492 GNUNET_free (cbs);
493 return GNUNET_NO;
494 }
495 return GNUNET_YES;
496}
497
498
499/**
500 * Remove a registered method from the try-and-slice instance.
501 *
502 * Removes one matching handler registered with the given
503 * @a method_name and callbacks.
504 *
505 * @param slicer
506 * The try-and-slice instance.
507 * @param method_name
508 * Name of the method to remove.
509 * @param method_cb
510 * Method handler.
511 * @param modifier_cb
512 * Modifier handler.
513 * @param data_cb
514 * Data handler.
515 * @param eom_cb
516 * End of message handler.
517 *
518 * @return #GNUNET_OK if a method handler was removed,
519 * #GNUNET_NO if no handler matched the given method name and callbacks.
520 */
521int
522GNUNET_PSYC_slicer_method_remove (struct GNUNET_PSYC_Slicer *slicer,
523 const char *method_name,
524 GNUNET_PSYC_MessageCallback msg_cb,
525 GNUNET_PSYC_MethodCallback method_cb,
526 GNUNET_PSYC_ModifierCallback modifier_cb,
527 GNUNET_PSYC_DataCallback data_cb,
528 GNUNET_PSYC_EndOfMessageCallback eom_cb)
529{
530 struct GNUNET_HashCode key;
531 GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key);
532
533 struct SlicerMethodRemoveClosure rm_cls;
534 rm_cls.slicer = slicer;
535 struct SlicerMethodCallbacks *rm_cbs = &rm_cls.rm_cbs;
536 rm_cbs->msg_cb = msg_cb;
537 rm_cbs->method_cb = method_cb;
538 rm_cbs->modifier_cb = modifier_cb;
539 rm_cbs->data_cb = data_cb;
540 rm_cbs->eom_cb = eom_cb;
541
542 return
543 (GNUNET_SYSERR
544 == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key,
545 slicer_method_remove,
546 &rm_cls))
547 ? GNUNET_NO
548 : GNUNET_OK;
549}
550
551
552/**
553 * Watch a place for changed objects.
554 *
555 * @param slicer
556 * The try-and-slice instance.
557 * @param object_filter
558 * Object prefix to match.
559 * @param modifier_cb
560 * Function to call when encountering a state modifier.
561 * @param cls
562 * Closure for callback.
563 */
564void
565GNUNET_PSYC_slicer_modifier_add (struct GNUNET_PSYC_Slicer *slicer,
566 const char *object_filter,
567 GNUNET_PSYC_ModifierCallback modifier_cb,
568 void *cls)
569{
570 struct SlicerModifierCallbacks *cbs = GNUNET_malloc (sizeof *cbs);
571 cbs->modifier_cb = modifier_cb;
572 cbs->cls = cls;
573
574 struct GNUNET_HashCode key;
575 GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key);
576 GNUNET_CONTAINER_multihashmap_put (slicer->modifier_handlers, &key, cbs,
577 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
578}
579
580
581static int
582slicer_modifier_remove (void *cls, const struct GNUNET_HashCode *key, void *value)
583{
584 struct SlicerModifierRemoveClosure *rm_cls = cls;
585 struct GNUNET_PSYC_Slicer *slicer = rm_cls->slicer;
586 struct SlicerModifierCallbacks *rm_cbs = &rm_cls->rm_cbs;
587 struct SlicerModifierCallbacks *cbs = value;
588
589 if (cbs->modifier_cb == rm_cbs->modifier_cb)
590 {
591 GNUNET_CONTAINER_multihashmap_remove (slicer->modifier_handlers, key, cbs);
592 GNUNET_free (cbs);
593 return GNUNET_NO;
594 }
595 return GNUNET_YES;
596}
597
598
599/**
600 * Remove a registered modifier from the try-and-slice instance.
601 *
602 * Removes one matching handler registered with the given
603 * @a object_filter and @a modifier_cb.
604 *
605 * @param slicer
606 * The try-and-slice instance.
607 * @param object_filter
608 * Object prefix to match.
609 * @param modifier_cb
610 * Function to call when encountering a state modifier changes.
611 */
612int
613GNUNET_PSYC_slicer_modifier_remove (struct GNUNET_PSYC_Slicer *slicer,
614 const char *object_filter,
615 GNUNET_PSYC_ModifierCallback modifier_cb)
616{
617 struct GNUNET_HashCode key;
618 GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key);
619
620 struct SlicerModifierRemoveClosure rm_cls;
621 rm_cls.slicer = slicer;
622 struct SlicerModifierCallbacks *rm_cbs = &rm_cls.rm_cbs;
623 rm_cbs->modifier_cb = modifier_cb;
624
625 return
626 (GNUNET_SYSERR
627 == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key,
628 slicer_modifier_remove,
629 &rm_cls))
630 ? GNUNET_NO
631 : GNUNET_OK;
632 }
633
634
635static int
636slicer_method_free (void *cls, const struct GNUNET_HashCode *key, void *value)
637{
638 struct SlicerMethodCallbacks *cbs = value;
639 GNUNET_free (cbs);
640 return GNUNET_YES;
641}
642
643
644static int
645slicer_modifier_free (void *cls, const struct GNUNET_HashCode *key, void *value)
646{
647 struct SlicerModifierCallbacks *cbs = value;
648 GNUNET_free (cbs);
649 return GNUNET_YES;
650}
651
652
653/**
654 * Remove all registered method handlers.
655 *
656 * @param slicer
657 * Slicer to clear.
658 */
659void
660GNUNET_PSYC_slicer_method_clear (struct GNUNET_PSYC_Slicer *slicer)
661{
662 GNUNET_CONTAINER_multihashmap_iterate (slicer->method_handlers,
663 slicer_method_free, NULL);
664 GNUNET_CONTAINER_multihashmap_clear (slicer->method_handlers);
665}
666
667
668/**
669 * Remove all registered modifier handlers.
670 *
671 * @param slicer
672 * Slicer to clear.
673 */
674void
675GNUNET_PSYC_slicer_modifier_clear (struct GNUNET_PSYC_Slicer *slicer)
676{
677 GNUNET_CONTAINER_multihashmap_iterate (slicer->modifier_handlers,
678 slicer_modifier_free, NULL);
679 GNUNET_CONTAINER_multihashmap_clear (slicer->modifier_handlers);
680}
681
682
683/**
684 * Remove all registered method & modifier handlers.
685 *
686 * @param slicer
687 * Slicer to clear.
688 */
689void
690GNUNET_PSYC_slicer_clear (struct GNUNET_PSYC_Slicer *slicer)
691{
692 GNUNET_PSYC_slicer_method_clear (slicer);
693 GNUNET_PSYC_slicer_modifier_clear (slicer);
694}
695
696
697/**
698 * Destroy a given try-and-slice instance.
699 *
700 * @param slicer
701 * Slicer to destroy
702 */
703void
704GNUNET_PSYC_slicer_destroy (struct GNUNET_PSYC_Slicer *slicer)
705{
706 GNUNET_PSYC_slicer_clear (slicer);
707 GNUNET_CONTAINER_multihashmap_destroy (slicer->method_handlers);
708 GNUNET_CONTAINER_multihashmap_destroy (slicer->modifier_handlers);
709 GNUNET_PSYC_receive_destroy (slicer->recv);
710 GNUNET_free (slicer);
711}
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 @@
1/*
2 * This file is part of GNUnet.
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @author Gabor X Toth
23 *
24 * @file
25 * Tests for the environment library.
26 */
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_testing_lib.h"
31#include "gnunet_psyc_util_lib.h"
32
33struct GNUNET_PSYC_Modifier mods[] = {
34 { .oper = GNUNET_PSYC_OP_SET,
35 .name = "_foo", .value = "foo", .value_size = 3 },
36
37 { .oper = GNUNET_PSYC_OP_ASSIGN,
38 .name = "_foo_bar", .value = "foo bar", .value_size = 7 },
39
40 { .oper = GNUNET_PSYC_OP_AUGMENT,
41 .name = "_foo_bar_baz", .value = "foo bar baz", .value_size = 11 }
42};
43
44struct ItCls
45{
46 size_t n;
47};
48
49int
50iterator (void *cls, enum GNUNET_PSYC_Operator oper,
51 const char *name, const char *value, uint32_t value_size)
52{
53 struct ItCls *it_cls = cls;
54 struct GNUNET_PSYC_Modifier *m = &mods[it_cls->n++];
55
56 GNUNET_assert (oper == m->oper);
57 GNUNET_assert (value_size == m->value_size);
58 GNUNET_assert (0 == memcmp (name, m->name, strlen (m->name)));
59 GNUNET_assert (0 == memcmp (value, m->value, m->value_size));
60
61 return GNUNET_YES;
62}
63
64int
65main (int argc, char *argv[])
66{
67 GNUNET_log_setup ("test-env", "WARNING", NULL);
68
69 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
70 GNUNET_assert (NULL != env);
71 int i, len = 3;
72
73 for (i = 0; i < len; i++)
74 {
75 GNUNET_PSYC_env_add (env, mods[i].oper, mods[i].name,
76 mods[i].value, mods[i].value_size);
77 }
78
79 struct ItCls it_cls = { .n = 0 };
80 GNUNET_PSYC_env_iterate (env, iterator, &it_cls);
81 GNUNET_assert (len == it_cls.n);
82
83 for (i = 0; i < len; i++)
84 {
85 enum GNUNET_PSYC_Operator oper;
86 const char *name;
87 const void *value;
88 size_t value_size;
89 GNUNET_PSYC_env_shift (env, &oper, &name, &value, &value_size);
90 GNUNET_assert (len - i - 1 == GNUNET_PSYC_env_get_count (env));
91 }
92
93 GNUNET_PSYC_env_destroy (env);
94
95 return 0;
96}
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 @@
1gnunet-social
2gnunet-service-social
3test_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 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4pkgcfgdir= $(pkgdatadir)/config.d/
5
6libexecdir= $(pkglibdir)/libexec/
7
8pkgcfg_DATA = \
9 social.conf
10
11
12if MINGW
13 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
14endif
15
16if USE_COVERAGE
17 AM_CFLAGS = --coverage -O0
18 XLIB = -lgcov
19endif
20
21lib_LTLIBRARIES = libgnunetsocial.la
22
23libgnunetsocial_la_SOURCES = \
24 social_api.c social.h
25libgnunetsocial_la_LIBADD = \
26 $(top_builddir)/src/util/libgnunetutil.la \
27 $(top_builddir)/src/psycutil/libgnunetpsycutil.la \
28 $(GN_LIBINTL) $(XLIB)
29libgnunetsocial_la_LDFLAGS = \
30 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
31 -version-info 0:0:0
32
33bin_PROGRAMS = \
34 gnunet-social
35
36libexec_PROGRAMS = \
37 gnunet-service-social
38
39gnunet_social_SOURCES = \
40 gnunet-social.c
41gnunet_social_LDADD = \
42 libgnunetsocial.la \
43 $(top_builddir)/src/psycutil/libgnunetpsycutil.la \
44 $(top_builddir)/src/util/libgnunetutil.la
45
46gnunet_service_social_SOURCES = \
47 gnunet-service-social.c
48gnunet_service_social_LDADD = \
49 $(top_builddir)/src/util/libgnunetutil.la \
50 $(top_builddir)/src/statistics/libgnunetstatistics.la \
51 $(top_builddir)/src/psycutil/libgnunetpsycutil.la \
52 $(top_builddir)/src/psyc/libgnunetpsyc.la \
53 $(top_builddir)/src/identity/libgnunetidentity.la \
54 $(top_builddir)/src/gns/libgnunetgns.la \
55 $(top_builddir)/src/namestore/libgnunetnamestore.la \
56 $(GN_LIBINTL)
57
58
59if HAVE_TESTING
60check_PROGRAMS = \
61 test_social
62endif
63
64if ENABLE_TEST_RUN
65AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
66TESTS = $(check_PROGRAMS)
67endif
68
69test_social_SOURCES = \
70 test_social.c
71test_social_LDADD = \
72 libgnunetsocial.la \
73 $(top_builddir)/src/testing/libgnunettesting.la \
74 $(top_builddir)/src/util/libgnunetutil.la \
75 $(top_builddir)/src/psycutil/libgnunetpsycutil.la \
76 $(top_builddir)/src/identity/libgnunetidentity.la
77
78EXTRA_DIST = \
79 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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file social/gnunet-service-social.c
23 * @brief Social service
24 * @author Gabor X Toth
25 */
26
27#include <inttypes.h>
28#include <strings.h>
29
30#include "platform.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_constants.h"
33#include "gnunet_protocols.h"
34#include "gnunet_identity_service.h"
35#include "gnunet_namestore_service.h"
36#include "gnunet_gns_service.h"
37#include "gnunet_statistics_service.h"
38#include "gnunet_psyc_service.h"
39#include "gnunet_psyc_util_lib.h"
40#include "gnunet_social_service.h"
41#include "social.h"
42
43
44/**
45 * Handle to our current configuration.
46 */
47static const struct GNUNET_CONFIGURATION_Handle *cfg;
48
49/**
50 * Service handle.
51 */
52static struct GNUNET_SERVICE_Handle *service;
53
54/* Handles to other services */
55static struct GNUNET_IDENTITY_Handle *id;
56static struct GNUNET_GNS_Handle *gns;
57static struct GNUNET_NAMESTORE_Handle *namestore;
58static struct GNUNET_STATISTICS_Handle *stats;
59
60/**
61 * ID of this peer.
62 */
63static struct GNUNET_PeerIdentity this_peer;
64
65/**
66 * All connected hosts.
67 * H(place_pub_key) -> struct Host
68 */
69static struct GNUNET_CONTAINER_MultiHashMap *hosts;
70
71/**
72 * All connected guests.
73 * H(place_pub_key) -> struct Guest
74 */
75static struct GNUNET_CONTAINER_MultiHashMap *guests;
76
77/**
78 * Connected guests per place.
79 * H(place_pub_key) -> ego_pub_key -> struct Guest
80 */
81static struct GNUNET_CONTAINER_MultiHashMap *place_guests;
82
83/**
84 * Places entered as host or guest.
85 * H(place_pub_key) -> struct HostEnterRequest OR struct GuestEnterRequest
86 */
87static struct GNUNET_CONTAINER_MultiHashMap *places;
88
89/**
90 * Places entered per application.
91 * H(app_id) -> H(place_pub_key) -> NULL
92 */
93static struct GNUNET_CONTAINER_MultiHashMap *apps_places;
94
95/**
96 * Application subscriptions per place.
97 * H(place_pub_key) -> H(app_id)
98 */
99//static struct GNUNET_CONTAINER_MultiHashMap *places_apps;
100
101/**
102 * Connected applications.
103 * H(app_id) -> struct Application
104 */
105static struct GNUNET_CONTAINER_MultiHashMap *apps;
106
107/**
108 * All egos.
109 * H(ego_pub_key) -> struct Ego
110 */
111static struct GNUNET_CONTAINER_MultiHashMap *egos;
112
113/**
114 * Directory for storing social data.
115 * Default: $GNUNET_DATA_HOME/social
116 */
117static char *dir_social;
118
119/**
120 * Directory for storing place data.
121 * $dir_social/places
122 */
123static char *dir_places;
124
125/**
126 * Directory for storing app data.
127 * $dir_social/apps
128 */
129static char *dir_apps;
130
131
132/**
133 * Message fragment transmission queue.
134 */
135struct FragmentTransmitQueue
136{
137 struct FragmentTransmitQueue *prev;
138 struct FragmentTransmitQueue *next;
139
140 struct GNUNET_SERVICE_Client *client;
141
142 /**
143 * Pointer to the next message part inside the data after this struct.
144 */
145 struct GNUNET_MessageHeader *next_part;
146
147 /**
148 * Size of message.
149 */
150 uint16_t size;
151
152 /**
153 * @see enum GNUNET_PSYC_MessageState
154 */
155 uint8_t state;
156
157 /* Followed by one or more message parts. */
158};
159
160
161/**
162 * Message transmission queue.
163 */
164struct MessageTransmitQueue
165{
166 struct MessageTransmitQueue *prev;
167 struct MessageTransmitQueue *next;
168
169 struct FragmentTransmitQueue *frags_head;
170 struct FragmentTransmitQueue *frags_tail;
171
172 struct GNUNET_SERVICE_Client *client;
173};
174
175/**
176 * List of connected clients.
177 */
178struct ClientListItem
179{
180 struct ClientListItem *prev;
181 struct ClientListItem *next;
182
183 struct GNUNET_SERVICE_Client *client;
184};
185
186
187/**
188 * Common part of the client context for both a host and guest.
189 */
190struct Place
191{
192 struct ClientListItem *clients_head;
193 struct ClientListItem *clients_tail;
194
195 struct MessageTransmitQueue *tmit_msgs_head;
196 struct MessageTransmitQueue *tmit_msgs_tail;
197
198 struct GNUNET_PSYC_Channel *channel;
199
200 /**
201 * Private key of home in case of a host.
202 */
203 struct GNUNET_CRYPTO_EddsaPublicKey key;
204
205 /**
206 * Public key of place.
207 */
208 struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
209
210 /**
211 * Hash of @a pub_key.
212 */
213 struct GNUNET_HashCode pub_key_hash;
214
215 /**
216 * Private key of ego.
217 */
218 struct GNUNET_CRYPTO_EcdsaPrivateKey ego_key;
219
220 /**
221 * Public key of ego.
222 */
223 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
224
225 /**
226 * Hash of @a ego_pub_key.
227 */
228 struct GNUNET_HashCode ego_pub_hash;
229
230 /**
231 * Slicer for processing incoming messages.
232 */
233 struct GNUNET_PSYC_Slicer *slicer;
234
235 /**
236 * Last message ID received for the place.
237 * 0 if there is no such message.
238 */
239 uint64_t max_message_id;
240
241 /**
242 * Offset where the file is currently being written.
243 */
244 uint64_t file_offset;
245
246 /**
247 * Whether or not to save the file (#GNUNET_YES or #GNUNET_NO)
248 */
249 uint8_t file_save;
250
251 /**
252 * Is this place ready to receive messages from client?
253 * #GNUNET_YES or #GNUNET_NO
254 */
255 uint8_t is_ready;
256
257 /**
258 * Is the client disconnecting?
259 * #GNUNET_YES or #GNUNET_NO
260 */
261 uint8_t is_disconnecting;
262
263 /**
264 * Is this a host (#GNUNET_YES), or guest (#GNUNET_NO)?
265 */
266 uint8_t is_host;
267
268 union {
269 struct Host *host;
270 struct Guest *guest;
271 };
272};
273
274
275/**
276 * Client context for a host.
277 */
278struct Host
279{
280 /**
281 * Place struct common for Host and Guest
282 */
283 struct Place place;
284
285 /**
286 * Handle for the multicast origin.
287 */
288 struct GNUNET_PSYC_Master *master;
289
290 /**
291 * Transmit handle for multicast.
292 */
293 struct GNUNET_PSYC_MasterTransmitHandle *tmit_handle;
294
295 /**
296 * Incoming join requests.
297 * guest_key -> struct GNUNET_PSYC_JoinHandle *
298 */
299 struct GNUNET_CONTAINER_MultiHashMap *join_reqs;
300
301 /**
302 * Messages being relayed.
303 */
304 struct GNUNET_CONTAINER_MultiHashMap *relay_msgs;
305
306 /**
307 * @see enum GNUNET_PSYC_Policy
308 */
309 enum GNUNET_PSYC_Policy policy;
310};
311
312
313/**
314 * Client context for a guest.
315 */
316struct Guest
317{
318 /**
319 * Place struct common for Host and Guest.
320 */
321 struct Place place;
322
323 /**
324 * Handle for the PSYC slave.
325 */
326 struct GNUNET_PSYC_Slave *slave;
327
328 /**
329 * Transmit handle for multicast.
330 */
331 struct GNUNET_PSYC_SlaveTransmitHandle *tmit_handle;
332
333 /**
334 * Peer identity of the origin.
335 */
336 struct GNUNET_PeerIdentity origin;
337
338 /**
339 * Number of items in @a relays.
340 */
341 uint32_t relay_count;
342
343 /**
344 * Relays that multicast can use to connect.
345 */
346 struct GNUNET_PeerIdentity *relays;
347
348 /**
349 * Join request to be transmitted to the master on join.
350 */
351 struct GNUNET_MessageHeader *join_req; // FIXME: not used!
352
353 /**
354 * Join decision received from PSYC.
355 */
356 struct GNUNET_PSYC_JoinDecisionMessage *join_dcsn;
357
358 /**
359 * Join flags for the PSYC service.
360 */
361 enum GNUNET_PSYC_SlaveJoinFlags join_flags;
362};
363
364
365/**
366 * Context for a client.
367 */
368struct Client
369{
370 /**
371 * Client handle.
372 */
373 struct GNUNET_SERVICE_Client *client;
374
375 /**
376 * Place where the client entered.
377 */
378 struct Place *place;
379
380 /**
381 * Message queue for the message currently being transmitted
382 * by this client.
383 */
384 struct MessageTransmitQueue *tmit_msg;
385
386 /**
387 * ID for application clients.
388 */
389 char *app_id;
390};
391
392
393struct Application
394{
395 struct ClientListItem *clients_head;
396 struct ClientListItem *clients_tail;
397};
398
399
400struct Ego {
401 struct GNUNET_CRYPTO_EcdsaPrivateKey key;
402 char *name;
403};
404
405
406struct OperationClosure
407{
408 struct Client *client;
409 uint64_t op_id;
410 uint32_t flags;
411};
412
413
414static int
415psyc_transmit_message (struct Place *plc);
416
417
418/**
419 * Clean up place data structures after a client disconnected.
420 *
421 * @param cls the `struct Place` to clean up
422 */
423static void
424cleanup_place (void *cls);
425
426
427static struct MessageTransmitQueue *
428psyc_transmit_queue_message (struct Place *plc,
429 struct GNUNET_SERVICE_Client *client,
430 size_t data_size,
431 const void *data,
432 uint16_t first_ptype, uint16_t last_ptype,
433 struct MessageTransmitQueue *tmit_msg);
434
435
436static int
437place_entry_cleanup (void *cls,
438 const struct GNUNET_HashCode *key,
439 void *value)
440{
441 struct Place *plc = value;
442
443 cleanup_place (plc);
444 return GNUNET_YES;
445}
446
447
448/**
449 * Task run during shutdown.
450 *
451 * @param cls unused
452 */
453static void
454shutdown_task (void *cls)
455{
456 GNUNET_CONTAINER_multihashmap_iterate (hosts, place_entry_cleanup, NULL);
457 GNUNET_CONTAINER_multihashmap_iterate (guests, place_entry_cleanup, NULL);
458
459 if (NULL != id)
460 {
461 GNUNET_IDENTITY_disconnect (id);
462 id = NULL;
463 }
464 if (NULL != namestore)
465 {
466 GNUNET_NAMESTORE_disconnect (namestore);
467 namestore = NULL;
468 }
469 if (NULL != gns)
470 {
471 GNUNET_GNS_disconnect (gns);
472 gns = NULL;
473 }
474 if (NULL != stats)
475 {
476 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
477 stats = NULL;
478 }
479}
480
481
482/**
483 * Clean up host data structures after a client disconnected.
484 */
485static void
486cleanup_host (struct Host *hst)
487{
488 struct Place *plc = &hst->place;
489
490 GNUNET_CONTAINER_multihashmap_destroy (hst->join_reqs);
491 GNUNET_CONTAINER_multihashmap_destroy (hst->relay_msgs);
492 GNUNET_CONTAINER_multihashmap_remove (hosts, &plc->pub_key_hash, plc);
493}
494
495
496/**
497 * Clean up guest data structures after a client disconnected.
498 */
499static void
500cleanup_guest (struct Guest *gst)
501{
502 struct Place *plc = &gst->place;
503 struct GNUNET_CONTAINER_MultiHashMap *
504 plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests,
505 &plc->pub_key_hash);
506 if (NULL != plc_gst)
507 {
508 GNUNET_CONTAINER_multihashmap_remove (plc_gst, &plc->ego_pub_hash, gst);
509
510 if (0 == GNUNET_CONTAINER_multihashmap_size (plc_gst))
511 {
512 GNUNET_CONTAINER_multihashmap_remove (place_guests, &plc->pub_key_hash,
513 plc_gst);
514 GNUNET_CONTAINER_multihashmap_destroy (plc_gst);
515 }
516 }
517 GNUNET_CONTAINER_multihashmap_remove (guests, &plc->pub_key_hash, gst);
518 if (NULL != gst->join_req)
519 GNUNET_free (gst->join_req);
520 if (NULL != gst->relays)
521 GNUNET_free (gst->relays);
522 GNUNET_CONTAINER_multihashmap_remove (guests, &plc->pub_key_hash, plc);
523}
524
525
526/**
527 * Clean up place data structures after a client disconnected.
528 *
529 * @param cls the `struct Place` to clean up
530 */
531static void
532cleanup_place (void *cls)
533{
534 struct Place *plc = cls;
535
536 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
537 "cleaning up place %s\n",
538 GNUNET_h2s (&plc->pub_key_hash));
539
540 (GNUNET_YES == plc->is_host)
541 ? cleanup_host ((struct Host *) plc)
542 : cleanup_guest ((struct Guest *) plc);
543
544 GNUNET_PSYC_slicer_destroy (plc->slicer);
545 GNUNET_free (plc);
546}
547
548
549/**
550 * Called whenever a client is disconnected.
551 * Frees our resources associated with that client.
552 *
553 * @param cls closure
554 * @param client identification of the client
555 * @param app_ctx must match @a client
556 */
557static void
558client_notify_disconnect (void *cls,
559 struct GNUNET_SERVICE_Client *client,
560 void *app_ctx)
561{
562 struct Client *c = app_ctx;
563 struct Place *plc = c->place;
564
565 if (NULL != c->app_id)
566 GNUNET_free (c->app_id);
567
568 GNUNET_free (c);
569
570 if (NULL == plc)
571 return; // application client, nothing to do
572
573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
574 "%p Client (%s) disconnected from place %s\n",
575 plc, (GNUNET_YES == plc->is_host) ? "host" : "guest",
576 GNUNET_h2s (&plc->pub_key_hash));
577
578 struct ClientListItem *cli = plc->clients_head;
579 while (NULL != cli)
580 {
581 if (cli->client == client)
582 {
583 GNUNET_CONTAINER_DLL_remove (plc->clients_head,
584 plc->clients_tail,
585 cli);
586 GNUNET_free (cli);
587 break;
588 }
589 cli = cli->next;
590 }
591 if (GNUNET_YES == plc->is_disconnecting)
592 {
593 GNUNET_PSYC_slicer_destroy (plc->slicer);
594 GNUNET_free (plc);
595 }
596}
597
598
599/**
600 * A new client connected.
601 *
602 * @param cls NULL
603 * @param client client to add
604 * @param mq message queue for @a client
605 * @return @a client
606 */
607static void *
608client_notify_connect (void *cls,
609 struct GNUNET_SERVICE_Client *client,
610 struct GNUNET_MQ_Handle *mq)
611{
612 struct Client *c = GNUNET_new (struct Client);
613
614 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
615 "Client %p connected with queue %p\n",
616 client,
617 mq);
618 c->client = client;
619 return c;
620}
621
622
623/**
624 * Send message to all clients connected to a place and
625 * takes care of freeing @env.
626 */
627static void
628place_send_msg (const struct Place *plc,
629 struct GNUNET_MQ_Envelope *env)
630{
631 struct ClientListItem *cli = plc->clients_head;
632
633 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
634 "%p Sending message to clients of place.\n", plc);
635 while (NULL != cli)
636 {
637 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
638 "Sending message to client %p\n",
639 cli);
640 GNUNET_MQ_send_copy (GNUNET_SERVICE_client_get_mq (cli->client),
641 env);
642 cli = cli->next;
643 }
644 GNUNET_MQ_discard (env);
645}
646
647
648static void
649place_send_leave_ack (struct Place *plc)
650{
651 struct GNUNET_MQ_Envelope *env;
652
653 for (struct ClientListItem *cli = plc->clients_head;
654 NULL != cli;
655 cli = cli->next)
656 {
657 env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE_ACK);
658 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (cli->client),
659 env);
660 }
661}
662
663
664/**
665 * Send a result code back to the client.
666 *
667 * @param client
668 * Client that should receive the result code.
669 * @param result_code
670 * Code to transmit.
671 * @param op_id
672 * Operation ID in network byte order.
673 * @param data
674 * Data payload or NULL.
675 * @param data_size
676 * Size of @a data.
677 */
678static void
679client_send_result (struct GNUNET_SERVICE_Client *client, uint64_t op_id,
680 int64_t result_code, const void *data, uint16_t data_size)
681{
682 struct GNUNET_MQ_Envelope *env;
683 struct GNUNET_OperationResultMessage *res;
684
685 env = GNUNET_MQ_msg_extra (res,
686 data_size,
687 GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE);
688 res->result_code = GNUNET_htonll (result_code);
689 res->op_id = op_id;
690 if (0 < data_size)
691 GNUNET_memcpy (&res[1], data, data_size);
692 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
693 "%p Sending result to client for operation #%" PRIu64 ": "
694 "%" PRId64 " (size: %u)\n",
695 client, GNUNET_ntohll (op_id), result_code, data_size);
696 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
697}
698
699
700static void
701client_send_host_enter_ack (struct GNUNET_SERVICE_Client *client,
702 struct Host *hst, uint32_t result)
703{
704 struct GNUNET_MQ_Envelope *env;
705 struct HostEnterAck *hack;
706 struct Place *plc = &hst->place;
707
708 env = GNUNET_MQ_msg (hack,
709 GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK);
710 hack->result_code = htonl (result);
711 hack->max_message_id = GNUNET_htonll (plc->max_message_id);
712 hack->place_pub_key = plc->pub_key;
713
714 if (NULL != client)
715 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
716 env);
717 else
718 place_send_msg (plc, env);
719}
720
721
722/**
723 * Called after a PSYC master is started.
724 */
725static void
726psyc_master_started (void *cls, int result, uint64_t max_message_id)
727{
728 struct Host *hst = cls;
729 struct Place *plc = &hst->place;
730 plc->max_message_id = max_message_id;
731 plc->is_ready = GNUNET_YES;
732
733 client_send_host_enter_ack (NULL, hst, result);
734}
735
736
737/**
738 * Called when a PSYC master receives a join request.
739 */
740static void
741psyc_recv_join_request (void *cls,
742 const struct GNUNET_PSYC_JoinRequestMessage *req,
743 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
744 const struct GNUNET_PSYC_Message *join_msg,
745 struct GNUNET_PSYC_JoinHandle *jh)
746{
747 struct Host *hst = cls;
748 struct GNUNET_HashCode slave_key_hash;
749 GNUNET_CRYPTO_hash (slave_key, sizeof (*slave_key), &slave_key_hash);
750 GNUNET_CONTAINER_multihashmap_put (hst->join_reqs, &slave_key_hash, jh,
751 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
752 place_send_msg (&hst->place,
753 GNUNET_MQ_msg_copy (&req->header));
754}
755
756
757/**
758 * Called after a PSYC slave is connected.
759 */
760static void
761psyc_slave_connected (void *cls, int result, uint64_t max_message_id)
762{
763 struct GNUNET_PSYC_CountersResultMessage *res;
764 struct GNUNET_MQ_Envelope *env;
765 struct Guest *gst = cls;
766 struct Place *plc = &gst->place;
767
768 plc->max_message_id = max_message_id;
769 plc->is_ready = GNUNET_YES;
770 env = GNUNET_MQ_msg (res,
771 GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK);
772 res->result_code =
773 (result != GNUNET_SYSERR) ? htonl (GNUNET_OK) : htonl (GNUNET_SYSERR);
774 res->max_message_id = GNUNET_htonll (plc->max_message_id);
775 place_send_msg (plc, env);
776}
777
778
779static void
780slave_parted_after_join_decision (void *cls)
781{
782 struct Guest *gst = cls;
783
784 GNUNET_assert (NULL != gst->join_dcsn);
785 place_send_msg (&gst->place, GNUNET_MQ_msg_copy (&gst->join_dcsn->header));
786}
787
788
789/**
790 * Called when a PSYC slave receives a join decision.
791 */
792static void
793psyc_recv_join_dcsn (void *cls,
794 const struct GNUNET_PSYC_JoinDecisionMessage *dcsn,
795 int is_admitted,
796 const struct GNUNET_PSYC_Message *join_msg)
797{
798 struct Guest *gst = cls;
799
800 gst->join_dcsn = GNUNET_malloc (dcsn->header.size);
801 GNUNET_memcpy (gst->join_dcsn,
802 dcsn,
803 dcsn->header.size);
804 if (GNUNET_NO == is_admitted)
805 {
806 GNUNET_PSYC_slave_part (gst->slave,
807 GNUNET_NO,
808 &slave_parted_after_join_decision,
809 gst);
810 gst->slave = NULL;
811 return;
812 }
813 place_send_msg (&gst->place, GNUNET_MQ_msg_copy (&gst->join_dcsn->header));
814}
815
816
817/**
818 * Called when a PSYC master or slave receives a message.
819 */
820static void
821psyc_recv_message (void *cls,
822 const struct GNUNET_PSYC_MessageHeader *msg)
823{
824 struct Place *plc = cls;
825
826 char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&msg->slave_pub_key);
827 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
828 "%p Received PSYC message of size %u from %s.\n",
829 plc, ntohs (msg->header.size), str);
830 GNUNET_free (str);
831
832 GNUNET_PSYC_slicer_message (plc->slicer, msg);
833
834 place_send_msg (plc, GNUNET_MQ_msg_copy (&msg->header));
835}
836
837
838/**
839 * Relay a message part received from a guest to the the place.
840 *
841 * @param hst
842 * Host.
843 * @param pmsg
844 * Message part.
845 * @param nym_pub_key
846 * Nym the message is received from.
847 */
848static void
849host_relay_message_part (struct Host *hst,
850 const struct GNUNET_MessageHeader *pmsg,
851 const struct GNUNET_CRYPTO_EcdsaPublicKey *nym_pub_key)
852{
853 /* separate queue per nym */
854 struct GNUNET_HashCode nym_pub_hash;
855 GNUNET_CRYPTO_hash (nym_pub_key, sizeof (*nym_pub_key), &nym_pub_hash);
856
857 struct MessageTransmitQueue *
858 tmit_msg = GNUNET_CONTAINER_multihashmap_get (hst->relay_msgs, &nym_pub_hash);
859
860 uint16_t ptype = ntohs (pmsg->type);
861
862 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == ptype)
863 {
864 /* FIXME: last message was unfinished, cancel & remove from queue */
865 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
866 "FIXME: last message was unfinished.\n");
867 }
868
869 tmit_msg = psyc_transmit_queue_message (&hst->place, NULL, ntohs (pmsg->size),
870 pmsg, ptype, ptype, tmit_msg);
871
872 switch (ptype)
873 {
874 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
875 GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_put
876 (hst->relay_msgs, &nym_pub_hash, tmit_msg,
877 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
878 break;
879 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
880 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
881 GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove
882 (hst->relay_msgs, &nym_pub_hash, tmit_msg));
883 break;
884 }
885}
886
887
888/**
889 * Received a method to be relayed from a guest.
890 */
891static void
892place_recv_relay_method (void *cls,
893 const struct GNUNET_PSYC_MessageHeader *msg,
894 const struct GNUNET_PSYC_MessageMethod *meth,
895 uint64_t message_id,
896 const char *method_name)
897{
898 struct Place *plc = cls;
899
900 if (GNUNET_PSYC_MESSAGE_REQUEST & ntohs (msg->flags)
901 && GNUNET_YES == plc->is_host)
902 {
903 struct Host *hst = cls;
904 host_relay_message_part (hst, &meth->header, &msg->slave_pub_key);
905 }
906}
907
908
909/**
910 * Received a modifier to be relayed from a guest.
911 */
912static void
913place_recv_relay_modifier (void *cls,
914 const struct GNUNET_PSYC_MessageHeader *msg,
915 const struct GNUNET_MessageHeader *pmsg,
916 uint64_t message_id,
917 enum GNUNET_PSYC_Operator oper,
918 const char *name,
919 const void *value,
920 uint16_t value_size,
921 uint16_t full_value_size)
922{
923 struct Place *plc = cls;
924
925 if (GNUNET_PSYC_MESSAGE_REQUEST & ntohs (msg->flags)
926 && GNUNET_YES == plc->is_host)
927 {
928 struct Host *hst = cls;
929 host_relay_message_part (hst, pmsg, &msg->slave_pub_key);
930 }
931}
932
933/**
934 * Received a data fragment to be relayed from a guest.
935 */
936static void
937place_recv_relay_data (void *cls,
938 const struct GNUNET_PSYC_MessageHeader *msg,
939 const struct GNUNET_MessageHeader *pmsg,
940 uint64_t message_id,
941 const void *data,
942 uint16_t data_size)
943{
944 struct Place *plc = cls;
945
946 if (GNUNET_PSYC_MESSAGE_REQUEST & ntohs (msg->flags)
947 && GNUNET_YES == plc->is_host)
948 {
949 struct Host *hst = cls;
950 host_relay_message_part (hst, pmsg, &msg->slave_pub_key);
951 }
952}
953
954
955/**
956 * Received end of message to be relayed from a guest.
957 */
958static void
959place_recv_relay_eom (void *cls,
960 const struct GNUNET_PSYC_MessageHeader *msg,
961 const struct GNUNET_MessageHeader *pmsg,
962 uint64_t message_id,
963 uint8_t is_cancelled)
964{
965 struct Place *plc = cls;
966
967 if (GNUNET_PSYC_MESSAGE_REQUEST & ntohs (msg->flags)
968 && GNUNET_YES == plc->is_host)
969 {
970 struct Host *hst = cls;
971 host_relay_message_part (hst, pmsg, &msg->slave_pub_key);
972 }
973}
974
975
976/**
977 * Received a method to be saved to disk.
978 *
979 * Create a new file for writing the data part of the message into,
980 * if the file does not yet exist.
981 */
982static void
983place_recv_save_method (void *cls,
984 const struct GNUNET_PSYC_MessageHeader *msg,
985 const struct GNUNET_PSYC_MessageMethod *meth,
986 uint64_t message_id,
987 const char *method_name)
988{
989 struct Place *plc = cls;
990 plc->file_offset = 0;
991 plc->file_save = GNUNET_NO;
992
993 char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (&plc->pub_key);
994 char *filename = NULL;
995 GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%" PRIu64 ".part",
996 dir_social, DIR_SEPARATOR,
997 "files", DIR_SEPARATOR,
998 place_pub_str, DIR_SEPARATOR,
999 GNUNET_ntohll (msg->message_id));
1000 GNUNET_free (place_pub_str);
1001
1002 /* save if does not already exist */
1003 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
1004 {
1005 if (0 == GNUNET_DISK_fn_write (filename, NULL, 0,
1006 GNUNET_DISK_PERM_USER_READ
1007 | GNUNET_DISK_PERM_USER_WRITE))
1008 {
1009 plc->file_save = GNUNET_YES;
1010 }
1011 else
1012 {
1013 GNUNET_break (0);
1014 }
1015 }
1016 GNUNET_free (filename);
1017}
1018
1019
1020/**
1021 * Received a data fragment to be saved to disk.
1022 *
1023 * Append data fragment to the file.
1024 */
1025static void
1026place_recv_save_data (void *cls,
1027 const struct GNUNET_PSYC_MessageHeader *msg,
1028 const struct GNUNET_MessageHeader *pmsg,
1029 uint64_t message_id,
1030 const void *data,
1031 uint16_t data_size)
1032{
1033 struct Place *plc = cls;
1034 if (GNUNET_YES != plc->file_save)
1035 return;
1036
1037 char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (&plc->pub_key);
1038 char *filename = NULL;
1039 GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%" PRIu64 ".part",
1040 dir_social, DIR_SEPARATOR,
1041 "files", DIR_SEPARATOR,
1042 place_pub_str, DIR_SEPARATOR,
1043 GNUNET_ntohll (msg->message_id));
1044 GNUNET_free (place_pub_str);
1045 if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
1046 {
1047 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "create", filename);
1048 GNUNET_free (filename);
1049 return;
1050 }
1051
1052 struct GNUNET_DISK_FileHandle *
1053 fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_WRITE,
1054 GNUNET_DISK_PERM_NONE);
1055 if (NULL != fh)
1056 {
1057 if (plc->file_offset != GNUNET_DISK_file_seek
1058 (fh, plc->file_offset, GNUNET_DISK_SEEK_SET)) {
1059 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "seek", filename);
1060 GNUNET_DISK_file_close (fh);
1061 GNUNET_free (filename);
1062 return;
1063 }
1064 GNUNET_DISK_file_write (fh, data, data_size);
1065 GNUNET_DISK_file_close (fh);
1066 GNUNET_free (filename);
1067 }
1068 else
1069 {
1070 GNUNET_free (filename);
1071 GNUNET_break (0);
1072 }
1073 plc->file_offset += data_size;
1074}
1075
1076
1077/**
1078 * Received end of message to be saved to disk.
1079 *
1080 * Remove .part ending from the filename.
1081 */
1082static void
1083place_recv_save_eom (void *cls,
1084 const struct GNUNET_PSYC_MessageHeader *msg,
1085 const struct GNUNET_MessageHeader *pmsg,
1086 uint64_t message_id,
1087 uint8_t is_cancelled)
1088{
1089 struct Place *plc = cls;
1090 if (GNUNET_YES != plc->file_save)
1091 return;
1092
1093 char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (&plc->pub_key);
1094 char *fn = NULL;
1095 GNUNET_asprintf (&fn, "%s%c%s%c%s%c%" PRIu64,
1096 dir_social, DIR_SEPARATOR,
1097 "files", DIR_SEPARATOR,
1098 place_pub_str, DIR_SEPARATOR,
1099 GNUNET_ntohll (msg->message_id));
1100 GNUNET_free (place_pub_str);
1101 char *fn_part = NULL;
1102 GNUNET_asprintf (&fn_part, "%s.part", fn);
1103
1104 if (rename (fn_part, fn)) {
1105 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1106 "Failed to rename %s into %s: %s (%d)\n",
1107 fn_part, fn, strerror (errno), errno);
1108 }
1109
1110 GNUNET_free (fn);
1111 GNUNET_free (fn_part);
1112}
1113
1114
1115/**
1116 * Initialize place data structure.
1117 */
1118static void
1119place_init (struct Place *plc)
1120{
1121 plc->slicer = GNUNET_PSYC_slicer_create ();
1122}
1123
1124
1125/**
1126 * Add a place to the @e places hash map.
1127 *
1128 * @param ereq
1129 * Entry request.
1130 *
1131 * @return #GNUNET_OK if the place was added
1132 * #GNUNET_NO if the place already exists in the hash map
1133 * #GNUNET_SYSERR on error
1134 */
1135static int
1136place_add (const struct PlaceEnterRequest *ereq)
1137{
1138 struct EgoPlacePublicKey ego_place_pub_key = {
1139 .ego_pub_key = ereq->ego_pub_key,
1140 .place_pub_key = ereq->place_pub_key,
1141 };
1142 struct GNUNET_HashCode ego_place_pub_hash;
1143 GNUNET_CRYPTO_hash (&ego_place_pub_key, sizeof (ego_place_pub_key), &ego_place_pub_hash);
1144
1145 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1146 " ego_place_pub_hash = %s\n", GNUNET_h2s (&ego_place_pub_hash));
1147
1148 struct GNUNET_MessageHeader *
1149 place_msg = GNUNET_CONTAINER_multihashmap_get (places, &ego_place_pub_hash);
1150 if (NULL != place_msg)
1151 return GNUNET_NO;
1152
1153 place_msg = GNUNET_copy_message (&ereq->header);
1154 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (places, &ego_place_pub_hash, place_msg,
1155 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
1156 {
1157 GNUNET_break (0);
1158 GNUNET_free (place_msg);
1159 return GNUNET_SYSERR;
1160 }
1161
1162 return GNUNET_OK;
1163}
1164
1165/**
1166 * Add a place to the @e app_places hash map.
1167 *
1168 * @param app_id
1169 * Application ID.
1170 * @param ereq
1171 * Entry request.
1172 *
1173 * @return #GNUNET_OK if the place was added
1174 * #GNUNET_NO if the place already exists in the hash map
1175 * #GNUNET_SYSERR on error
1176 */
1177static int
1178app_place_add (const char *app_id,
1179 const struct PlaceEnterRequest *ereq)
1180{
1181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1182 "Adding app place to hashmap:\n");
1183 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1184 " app_id = %s\n", app_id);
1185
1186 struct GNUNET_HashCode app_id_hash;
1187 GNUNET_CRYPTO_hash (app_id, strlen (app_id) + 1, &app_id_hash);
1188
1189 struct EgoPlacePublicKey ego_place_pub_key = {
1190 .ego_pub_key = ereq->ego_pub_key,
1191 .place_pub_key = ereq->place_pub_key,
1192 };
1193 struct GNUNET_HashCode ego_place_pub_hash;
1194 GNUNET_CRYPTO_hash (&ego_place_pub_key, sizeof (ego_place_pub_key), &ego_place_pub_hash);
1195
1196 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1197 " ego_place_pub_hash = %s\n", GNUNET_h2s (&ego_place_pub_hash));
1198
1199 struct GNUNET_CONTAINER_MultiHashMap *
1200 app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash);
1201 if (NULL == app_places)
1202 {
1203 app_places = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1204 GNUNET_CONTAINER_multihashmap_put (apps_places, &app_id_hash, app_places,
1205 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1206 }
1207
1208 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (app_places, &ego_place_pub_hash))
1209 return GNUNET_NO;
1210
1211 if (GNUNET_SYSERR == place_add (ereq))
1212 {
1213 return GNUNET_SYSERR;
1214 }
1215
1216 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (app_places, &ego_place_pub_hash, NULL,
1217 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
1218 {
1219 GNUNET_break (0);
1220 return GNUNET_SYSERR;
1221 }
1222 return GNUNET_OK;
1223}
1224
1225
1226/**
1227 * Save place entry message to disk.
1228 *
1229 * @param app_id
1230 * Application ID.
1231 * @param ereq
1232 * Entry request message.
1233 */
1234static int
1235app_place_save (const char *app_id,
1236 const struct PlaceEnterRequest *ereq)
1237{
1238 if (GNUNET_SYSERR == app_place_add (app_id, ereq))
1239 {
1240 GNUNET_assert (0);
1241 }
1242
1243 if (NULL == dir_places)
1244 return GNUNET_SYSERR;
1245
1246 char *ego_pub_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&ereq->ego_pub_key);
1247 char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (&ereq->place_pub_key);
1248 char *filename = NULL;
1249 GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s",
1250 dir_social, DIR_SEPARATOR,
1251 "places", DIR_SEPARATOR,
1252 ego_pub_str, DIR_SEPARATOR,
1253 place_pub_str);
1254 int ret = GNUNET_DISK_directory_create_for_file (filename);
1255 if (GNUNET_OK != ret
1256 || 0 > GNUNET_DISK_fn_write (filename, ereq, ntohs (ereq->header.size),
1257 GNUNET_DISK_PERM_USER_READ
1258 | GNUNET_DISK_PERM_USER_WRITE))
1259 {
1260 GNUNET_break (0);
1261 ret = GNUNET_SYSERR;
1262 }
1263 GNUNET_free (filename);
1264
1265 if (ret == GNUNET_OK)
1266 {
1267 GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s%c" "%s",
1268 dir_social, DIR_SEPARATOR,
1269 "apps", DIR_SEPARATOR,
1270 app_id, DIR_SEPARATOR,
1271 ego_pub_str, DIR_SEPARATOR,
1272 place_pub_str);
1273 ret = GNUNET_DISK_directory_create_for_file (filename);
1274 if (GNUNET_OK != ret
1275 || 0 > GNUNET_DISK_fn_write (filename, "", 0,
1276 GNUNET_DISK_PERM_USER_READ
1277 | GNUNET_DISK_PERM_USER_WRITE))
1278 {
1279 GNUNET_break (0);
1280 ret = GNUNET_SYSERR;
1281 }
1282 GNUNET_free (filename);
1283 }
1284 GNUNET_free (ego_pub_str);
1285 GNUNET_free (place_pub_str);
1286 return ret;
1287}
1288
1289
1290int
1291app_place_remove (const char *app_id,
1292 const struct GNUNET_CRYPTO_EcdsaPublicKey *ego_pub_key,
1293 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key)
1294{
1295 struct GNUNET_HashCode ego_pub_hash;
1296 struct GNUNET_HashCode place_pub_hash;
1297 GNUNET_CRYPTO_hash (ego_pub_key, sizeof (*ego_pub_key), &ego_pub_hash);
1298 GNUNET_CRYPTO_hash (place_pub_key, sizeof (*place_pub_key), &place_pub_hash);
1299
1300 char *ego_pub_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (ego_pub_key);
1301 char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (place_pub_key);
1302 char *app_place_filename = NULL;
1303 GNUNET_asprintf (&app_place_filename,
1304 "%s%c" "%s%c" "%s%c" "%s%c" "%s",
1305 dir_social, DIR_SEPARATOR,
1306 "apps", DIR_SEPARATOR,
1307 app_id, DIR_SEPARATOR,
1308 ego_pub_str, DIR_SEPARATOR,
1309 place_pub_str);
1310 GNUNET_free (ego_pub_str);
1311 GNUNET_free (place_pub_str);
1312
1313 struct GNUNET_HashCode app_id_hash;
1314 GNUNET_CRYPTO_hash (app_id, strlen (app_id) + 1, &app_id_hash);
1315
1316 struct GNUNET_CONTAINER_MultiHashMap *
1317 app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash);
1318
1319 if (NULL != app_places)
1320 GNUNET_CONTAINER_multihashmap_remove (app_places, &place_pub_hash, NULL);
1321
1322 int ret = GNUNET_OK;
1323
1324 if (0 != unlink (app_place_filename))
1325 {
1326 GNUNET_break (0);
1327 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1328 "Error removing app place file: %s: %s (%d)\n",
1329 app_place_filename, strerror (errno), errno);
1330 ret = GNUNET_SYSERR;
1331 }
1332 GNUNET_free (app_place_filename);
1333
1334 return ret;
1335}
1336
1337
1338/**
1339 * Enter place as host.
1340 *
1341 * @param hreq
1342 * Host entry request.
1343 * @param[out] ret_hst
1344 * Returned Host struct.
1345 *
1346 * @return #GNUNET_YES if the host entered the place just now,
1347 * #GNUNET_NO if the place is already entered,
1348 * #GNUNET_SYSERR if place_pub_key was set
1349 * but its private key was not found
1350 */
1351static int
1352host_enter (const struct HostEnterRequest *hreq, struct Host **ret_hst)
1353{
1354 int ret = GNUNET_NO;
1355 struct GNUNET_HashCode place_pub_hash;
1356 GNUNET_CRYPTO_hash (&hreq->place_pub_key, sizeof (hreq->place_pub_key),
1357 &place_pub_hash);
1358 struct Host *hst = GNUNET_CONTAINER_multihashmap_get (hosts, &place_pub_hash);
1359
1360 if (NULL == hst)
1361 {
1362 hst = GNUNET_new (struct Host);
1363 hst->policy = hreq->policy;
1364 hst->join_reqs = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1365 hst->relay_msgs = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
1366
1367 struct Place *plc = &hst->place;
1368 place_init (plc);
1369 plc->is_host = GNUNET_YES;
1370 plc->pub_key = hreq->place_pub_key;
1371 plc->pub_key_hash = place_pub_hash;
1372
1373 GNUNET_CONTAINER_multihashmap_put (hosts, &plc->pub_key_hash, plc,
1374 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1375 hst->master = GNUNET_PSYC_master_start (cfg, &hreq->place_key, hst->policy,
1376 &psyc_master_started,
1377 &psyc_recv_join_request,
1378 &psyc_recv_message, NULL, hst);
1379 plc->channel = GNUNET_PSYC_master_get_channel (hst->master);
1380 ret = GNUNET_YES;
1381 }
1382
1383 if (NULL != ret_hst)
1384 *ret_hst = hst;
1385 return ret;
1386}
1387
1388
1389static int
1390msg_proc_parse (const struct MsgProcRequest *mpreq,
1391 uint32_t *flags,
1392 const char **method_prefix,
1393 struct GNUNET_HashCode *method_hash)
1394{
1395 ssize_t method_size = ntohs (mpreq->header.size) - sizeof (*mpreq);
1396 uint16_t offset;
1397
1398 if (method_size < 0)
1399 {
1400 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1401 "MsgProcRequest has invalid size\n");
1402 return GNUNET_SYSERR;
1403 }
1404
1405 offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &mpreq[1],
1406 method_size,
1407 1,
1408 method_prefix);
1409 if (0 == offset || offset != method_size || *method_prefix == NULL)
1410 {
1411 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1412 "MsgProcRequest contains invalid method\n");
1413 return GNUNET_SYSERR;
1414 }
1415 GNUNET_CRYPTO_hash (*method_prefix, (size_t) method_size, method_hash);
1416 *flags = ntohl (mpreq->flags);
1417 return GNUNET_OK;
1418}
1419
1420
1421void
1422app_notify_place (const struct GNUNET_MessageHeader *msg,
1423 struct GNUNET_SERVICE_Client *client)
1424{
1425 struct AppPlaceMessage *amsg;
1426 struct GNUNET_MQ_Envelope *env;
1427 uint16_t msg_size = ntohs (msg->size);
1428
1429 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1430 "%p Sending place notification of type %u to client.\n",
1431 client, ntohs (msg->type));
1432 switch (ntohs (msg->type))
1433 {
1434 case GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER:
1435 {
1436 struct HostEnterRequest *hreq = (struct HostEnterRequest *) msg;
1437 if (msg_size < sizeof (struct HostEnterRequest))
1438 return;
1439 env = GNUNET_MQ_msg (amsg,
1440 GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE);
1441 // FIXME: also notify about not entered places
1442 amsg->place_state = GNUNET_SOCIAL_PLACE_STATE_ENTERED;
1443 amsg->is_host = GNUNET_YES;
1444 amsg->ego_pub_key = hreq->ego_pub_key;
1445 amsg->place_pub_key = hreq->place_pub_key;
1446 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
1447 env);
1448 break;
1449 }
1450 case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER:
1451 {
1452 if (msg_size < sizeof (struct GuestEnterRequest))
1453 return;
1454 struct GuestEnterRequest *greq = (struct GuestEnterRequest *) msg;
1455 env = GNUNET_MQ_msg (amsg,
1456 GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE);
1457 // FIXME: also notify about not entered places
1458 amsg->place_state = GNUNET_SOCIAL_PLACE_STATE_ENTERED;
1459 amsg->is_host = GNUNET_NO;
1460 amsg->ego_pub_key = greq->ego_pub_key;
1461 amsg->place_pub_key = greq->place_pub_key;
1462 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
1463 env);
1464 break;
1465 }
1466 default:
1467 return;
1468 }
1469}
1470
1471
1472void
1473app_notify_place_end (struct GNUNET_SERVICE_Client *client)
1474{
1475 struct GNUNET_MQ_Envelope *env;
1476
1477 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1478 "%p Sending end of place list notification to client\n",
1479 client);
1480 env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE_END);
1481 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
1482 env);
1483}
1484
1485
1486void
1487app_notify_ego (struct Ego *ego, struct GNUNET_SERVICE_Client *client)
1488{
1489 struct AppEgoMessage *emsg;
1490 struct GNUNET_MQ_Envelope *env;
1491 size_t name_size = strlen (ego->name) + 1;
1492
1493 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1494 "%p Sending ego notification to client: %s\n",
1495 client, ego->name);
1496 env = GNUNET_MQ_msg_extra (emsg,
1497 name_size,
1498 GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO);
1499 GNUNET_CRYPTO_ecdsa_key_get_public (&ego->key, &emsg->ego_pub_key);
1500 GNUNET_memcpy (&emsg[1], ego->name, name_size);
1501 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
1502 env);
1503}
1504
1505
1506void
1507app_notify_ego_end (struct GNUNET_SERVICE_Client *client)
1508{
1509 struct GNUNET_MQ_Envelope *env;
1510
1511 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1512 "%p Sending end of ego list notification to client\n",
1513 client);
1514 env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO_END);
1515 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
1516 env);
1517}
1518
1519
1520int
1521app_place_entry_notify (void *cls, const struct GNUNET_HashCode *key, void *value)
1522{
1523 struct GNUNET_MessageHeader *
1524 msg = GNUNET_CONTAINER_multihashmap_get (places, key);
1525 if (NULL != msg)
1526 app_notify_place (msg, cls);
1527 return GNUNET_YES;
1528}
1529
1530
1531int
1532ego_entry (void *cls, const struct GNUNET_HashCode *key, void *value)
1533{
1534 app_notify_ego (value, cls);
1535 return GNUNET_YES;
1536}
1537
1538
1539static int
1540check_client_msg_proc_set (void *cls,
1541 const struct MsgProcRequest *mpreq)
1542{
1543 return GNUNET_OK;
1544}
1545
1546
1547/**
1548 * Handle a client setting message proccesing flags for a method prefix.
1549 */
1550static void
1551handle_client_msg_proc_set (void *cls,
1552 const struct MsgProcRequest *mpreq)
1553{
1554 struct Client *c = cls;
1555 struct GNUNET_SERVICE_Client *client = c->client;
1556 struct Place *plc = c->place;
1557 if (NULL == plc)
1558 {
1559 GNUNET_break (0);
1560 GNUNET_SERVICE_client_drop (client);
1561 return;
1562 }
1563
1564 const char *method_prefix = NULL;
1565 uint32_t flags = 0;
1566 struct GNUNET_HashCode method_hash;
1567
1568 if (GNUNET_OK !=
1569 msg_proc_parse (mpreq, &flags, &method_prefix, &method_hash))
1570 {
1571 GNUNET_break (0);
1572 GNUNET_SERVICE_client_drop (client);
1573 return;
1574 }
1575#if 0
1576 GNUNET_PSYC_slicer_method_remove (plc->slicer, method_prefix,
1577 place_recv_relay_method,
1578 place_recv_relay_modifier,
1579 place_recv_relay_data,
1580 place_recv_relay_eom);
1581 GNUNET_PSYC_slicer_method_remove (plc->slicer, method_prefix,
1582 place_recv_save_method,
1583 NULL,
1584 place_recv_save_data,
1585 place_recv_save_eom);
1586#endif
1587 if (flags & GNUNET_SOCIAL_MSG_PROC_RELAY)
1588 {
1589 GNUNET_PSYC_slicer_method_add (plc->slicer, method_prefix, NULL,
1590 place_recv_relay_method,
1591 place_recv_relay_modifier,
1592 place_recv_relay_data,
1593 place_recv_relay_eom,
1594 plc);
1595 }
1596 if (flags & GNUNET_SOCIAL_MSG_PROC_SAVE)
1597 {
1598 GNUNET_PSYC_slicer_method_add (plc->slicer, method_prefix, NULL,
1599 place_recv_save_method,
1600 NULL,
1601 place_recv_save_data,
1602 place_recv_save_eom,
1603 plc);
1604 }
1605
1606 /** @todo Save flags to be able to resume relaying/saving after restart */
1607
1608 GNUNET_SERVICE_client_continue (client);
1609}
1610
1611
1612/**
1613 * Handle a connecting client requesting to clear all relay rules.
1614 */
1615static void
1616handle_client_msg_proc_clear (void *cls,
1617 const struct GNUNET_MessageHeader *msg)
1618{
1619 struct Client *c = cls;
1620 struct GNUNET_SERVICE_Client *client = c->client;
1621 struct Place *plc = c->place;
1622 if (NULL == plc)
1623 {
1624 GNUNET_break (0);
1625 GNUNET_SERVICE_client_drop (client);
1626 return;
1627 }
1628
1629 GNUNET_PSYC_slicer_clear (plc->slicer);
1630
1631 GNUNET_SERVICE_client_continue (client);
1632}
1633
1634
1635static int
1636check_client_host_enter (void *cls,
1637 const struct HostEnterRequest *hr)
1638{
1639 return GNUNET_OK;
1640}
1641
1642
1643/**
1644 * Handle a connecting client entering a place as host.
1645 */
1646static void
1647handle_client_host_enter (void *cls,
1648 const struct HostEnterRequest *hr)
1649{
1650 struct Client *c = cls;
1651 struct GNUNET_SERVICE_Client *client = c->client;
1652 struct HostEnterRequest *
1653 hreq = (struct HostEnterRequest *) GNUNET_copy_message (&hr->header);
1654
1655 uint8_t app_id_size = ntohs (hreq->header.size) - sizeof (*hreq);
1656 const char *app_id = NULL;
1657 uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &hreq[1],
1658 app_id_size, 1, &app_id);
1659 if (0 == offset || offset != app_id_size || app_id == NULL)
1660 {
1661 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1662 "offset = %u, app_id_size = %u, app_id = %s\n",
1663 offset, app_id_size, app_id);
1664 GNUNET_break (0);
1665 GNUNET_SERVICE_client_drop (client);
1666 return;
1667 }
1668
1669 struct Host *hst = NULL;
1670 struct Place *plc = NULL;
1671 int ret = GNUNET_OK;
1672
1673 struct GNUNET_CRYPTO_EddsaPublicKey empty_pub_key;
1674 memset (&empty_pub_key, 0, sizeof (empty_pub_key));
1675
1676 if (0 == memcmp (&hreq->place_pub_key, &empty_pub_key, sizeof (empty_pub_key)))
1677 { // no public key set: create new private key & save the place
1678 struct GNUNET_CRYPTO_EddsaPrivateKey *
1679 place_key = GNUNET_CRYPTO_eddsa_key_create ();
1680 hreq->place_key = *place_key;
1681 GNUNET_CRYPTO_eddsa_key_get_public (place_key, &hreq->place_pub_key);
1682 GNUNET_CRYPTO_eddsa_key_clear (place_key);
1683 GNUNET_free (place_key);
1684
1685 app_place_save (app_id, (const struct PlaceEnterRequest *) hreq);
1686 }
1687
1688 switch (host_enter (hreq, &hst))
1689 {
1690 case GNUNET_YES:
1691 plc = c->place = &hst->place;
1692 plc->host = hst;
1693 break;
1694
1695 case GNUNET_NO:
1696 {
1697 plc = c->place = &hst->place;
1698 plc->host = hst;
1699 client_send_host_enter_ack (client, hst, GNUNET_OK);
1700 break;
1701 }
1702 case GNUNET_SYSERR:
1703 ret = GNUNET_SYSERR;
1704 }
1705
1706 if (ret != GNUNET_SYSERR)
1707 {
1708
1709 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1710 "%p Client connected as host to place %s.\n",
1711 hst, GNUNET_h2s (&plc->pub_key_hash));
1712
1713 struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
1714 cli->client = client;
1715 GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli);
1716 c->place = plc;
1717 app_notify_place (&hreq->header, client);
1718 }
1719
1720 GNUNET_CRYPTO_eddsa_key_clear (&hreq->place_key);
1721 GNUNET_free (hreq);
1722
1723 if (GNUNET_OK == ret)
1724 GNUNET_SERVICE_client_continue (client);
1725 else
1726 GNUNET_SERVICE_client_drop (client);
1727}
1728
1729
1730/**
1731 * Enter place as guest.
1732 *
1733 * @param greq
1734 * Guest entry request.
1735 * @param[out] ret_gst
1736 * Returned Guest struct.
1737 *
1738 * @return #GNUNET_YES if the guest entered the place just now,
1739 * #GNUNET_NO if the place is already entered,
1740 * #GNUNET_SYSERR on error.
1741 */
1742static int
1743guest_enter (const struct GuestEnterRequest *greq, struct Guest **ret_gst)
1744{
1745 int ret = GNUNET_NO;
1746 uint16_t greq_size = ntohs (greq->header.size);
1747
1748 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key = greq->ego_pub_key;
1749 struct GNUNET_HashCode ego_pub_hash;
1750 GNUNET_CRYPTO_hash (&ego_pub_key, sizeof (ego_pub_key), &ego_pub_hash);
1751 struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
1752
1753 if (NULL == ego)
1754 {
1755 return GNUNET_SYSERR;
1756 }
1757
1758 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1759 "entering as guest\n");
1760 struct GNUNET_HashCode place_pub_hash;
1761 GNUNET_CRYPTO_hash (&greq->place_pub_key, sizeof (greq->place_pub_key),
1762 &place_pub_hash);
1763
1764 struct GNUNET_CONTAINER_MultiHashMap *
1765 plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests, &place_pub_hash);
1766 struct Guest *gst = NULL;
1767 int new_guest;
1768
1769 if (NULL != plc_gst)
1770 gst = GNUNET_CONTAINER_multihashmap_get (plc_gst, &ego_pub_hash);
1771
1772 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1773 "plc_gst = %p, gst = %p\n",
1774 plc_gst,
1775 gst);
1776
1777 if (NULL == gst)
1778 {
1779 gst = GNUNET_new (struct Guest);
1780 new_guest = GNUNET_YES;
1781 }
1782 else new_guest = GNUNET_NO;
1783
1784 if (NULL == gst->slave)
1785 {
1786 gst->origin = greq->origin;
1787 gst->relay_count = ntohl (greq->relay_count);
1788
1789 uint16_t len;
1790 uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq);
1791 const char *app_id = (const char *) &greq[1];
1792 const char *p = app_id;
1793
1794 len = strnlen (app_id, remaining);
1795 if (len == remaining)
1796 {
1797 GNUNET_free (gst);
1798 GNUNET_break (0);
1799 return GNUNET_SYSERR;
1800 }
1801 p += len + 1;
1802 remaining -= len + 1;
1803
1804 const struct GNUNET_PeerIdentity *relays = NULL;
1805 uint16_t relay_size = gst->relay_count * sizeof (*relays);
1806 if (remaining < relay_size)
1807 {
1808 GNUNET_free (gst);
1809 GNUNET_break (0);
1810 return GNUNET_SYSERR;
1811 }
1812 if (0 < relay_size)
1813 relays = (const struct GNUNET_PeerIdentity *) p;
1814 p += relay_size;
1815 remaining -= relay_size;
1816
1817 struct GNUNET_PSYC_Message *join_msg = NULL;
1818 uint16_t join_msg_size = 0;
1819
1820 if (sizeof (struct GNUNET_MessageHeader) <= remaining)
1821 {
1822 join_msg = (struct GNUNET_PSYC_Message *) p;
1823 join_msg_size = ntohs (join_msg->header.size);
1824 p += join_msg_size;
1825 remaining -= join_msg_size;
1826 }
1827 if (0 != remaining)
1828 {
1829 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1830 "%zu + %u + %u != %u\n",
1831 sizeof (*greq), relay_size, join_msg_size, greq_size);
1832 GNUNET_free (gst);
1833 GNUNET_break (0);
1834 return GNUNET_SYSERR;
1835 }
1836 if (0 < relay_size)
1837 {
1838 gst->relays = GNUNET_malloc (relay_size);
1839 GNUNET_memcpy (gst->relays, relays, relay_size);
1840 }
1841
1842 gst->join_flags = ntohl (greq->flags);
1843
1844 struct Place *plc = &gst->place;
1845 place_init (plc);
1846 plc->is_host = GNUNET_NO;
1847 plc->pub_key = greq->place_pub_key;
1848 plc->pub_key_hash = place_pub_hash;
1849 plc->ego_pub_key = ego_pub_key;
1850 plc->ego_pub_hash = ego_pub_hash;
1851 plc->ego_key = ego->key;
1852
1853 if (NULL == plc_gst)
1854 {
1855 plc_gst = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
1856 (void) GNUNET_CONTAINER_multihashmap_put (place_guests, &plc->pub_key_hash, plc_gst,
1857 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1858 }
1859 if (GNUNET_YES == new_guest)
1860 {
1861 (void) GNUNET_CONTAINER_multihashmap_put (plc_gst, &plc->ego_pub_hash, gst,
1862 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1863 (void) GNUNET_CONTAINER_multihashmap_put (guests, &plc->pub_key_hash, gst,
1864 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1865
1866 }
1867 gst->slave
1868 = GNUNET_PSYC_slave_join (cfg, &plc->pub_key, &plc->ego_key,
1869 gst->join_flags, &gst->origin,
1870 gst->relay_count, gst->relays,
1871 &psyc_recv_message, NULL,
1872 &psyc_slave_connected,
1873 &psyc_recv_join_dcsn,
1874 gst, join_msg);
1875 plc->channel = GNUNET_PSYC_slave_get_channel (gst->slave);
1876 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1877 "slave entered channel %p\n",
1878 plc->channel);
1879 ret = GNUNET_YES;
1880 }
1881
1882 // TODO: explain to automatic code scanners why free(gst) not necessary
1883 if (NULL != ret_gst)
1884 *ret_gst = gst;
1885 return ret;
1886}
1887
1888
1889static int
1890client_guest_enter (struct Client *c,
1891 const struct GuestEnterRequest *greq)
1892{
1893 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1894 "client_guest_enter\n");
1895 struct GNUNET_PSYC_CountersResultMessage *result_msg;
1896 struct GNUNET_MQ_Envelope *env;
1897 struct GNUNET_SERVICE_Client *client = c->client;
1898 uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq);
1899 const char *app_id = NULL;
1900 uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &greq[1],
1901 remaining, 1, &app_id);
1902 struct Guest *gst = NULL;
1903 struct Place *plc = NULL;
1904
1905 if (0 == offset)
1906 {
1907 return GNUNET_SYSERR;
1908 }
1909 switch (guest_enter (greq, &gst))
1910 {
1911 case GNUNET_YES:
1912 {
1913 plc = c->place = &gst->place;
1914 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1915 "guest entered successfully to local place %s\n",
1916 GNUNET_h2s (&plc->pub_key_hash));
1917 plc->guest = gst;
1918 app_place_save (app_id, (const struct PlaceEnterRequest *) greq);
1919 app_notify_place (&greq->header, client);
1920 break;
1921 }
1922 case GNUNET_NO:
1923 {
1924 plc = c->place = &gst->place;
1925 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1926 "guest re-entered successfully to local place %s\n",
1927 GNUNET_h2s (&plc->pub_key_hash));
1928 plc->guest = gst;
1929 env = GNUNET_MQ_msg (result_msg,
1930 GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK);
1931 result_msg->result_code = htonl (GNUNET_OK);
1932 result_msg->max_message_id = GNUNET_htonll (plc->max_message_id);
1933 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
1934 env);
1935 if (NULL != gst->join_dcsn)
1936 {
1937 env = GNUNET_MQ_msg_copy (&gst->join_dcsn->header);
1938 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
1939 env);
1940 }
1941 break;
1942 }
1943 case GNUNET_SYSERR:
1944 {
1945 return GNUNET_SYSERR;
1946 }
1947 }
1948
1949 struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
1950 cli->client = client;
1951 GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli);
1952 return GNUNET_OK;
1953}
1954
1955
1956static int
1957check_client_guest_enter (void *cls,
1958 const struct GuestEnterRequest *greq)
1959{
1960 return GNUNET_OK;
1961}
1962
1963
1964/**
1965 * Handle a connecting client entering a place as guest.
1966 */
1967static void
1968handle_client_guest_enter (void *cls,
1969 const struct GuestEnterRequest *greq)
1970{
1971 struct Client *c = cls;
1972
1973 if (GNUNET_SYSERR == client_guest_enter (c, greq))
1974 {
1975 GNUNET_break (0);
1976 GNUNET_SERVICE_client_drop (c->client);
1977 return;
1978 }
1979 GNUNET_SERVICE_client_continue (c->client);
1980}
1981
1982
1983struct GuestEnterByNameClosure
1984{
1985 struct Client *client;
1986 char *app_id;
1987 char *password;
1988 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
1989 struct GNUNET_MessageHeader *join_msg;
1990};
1991
1992
1993/**
1994 * Result of a GNS name lookup for entering a place.
1995 *
1996 * @see GNUNET_SOCIAL_guest_enter_by_name
1997 */
1998static void
1999gns_result_guest_enter (void *cls, uint32_t rd_count,
2000 const struct GNUNET_GNSRECORD_Data *rd)
2001{
2002 struct GuestEnterByNameClosure *gcls = cls;
2003 struct Client *c = gcls->client;
2004 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2005 "%p GNS result: %u records.\n",
2006 c, rd_count);
2007
2008 const struct GNUNET_GNSRECORD_PlaceData *
2009 rec = (const struct GNUNET_GNSRECORD_PlaceData *) rd->data;
2010
2011 if (0 == rd_count || rd->data_size < sizeof (*rec))
2012 {
2013 GNUNET_break (0);
2014 GNUNET_SERVICE_client_drop (c->client);
2015 return;
2016 }
2017
2018 uint16_t relay_count = ntohl (rec->relay_count);
2019 struct GNUNET_PeerIdentity *relays = NULL;
2020
2021 if (0 < relay_count)
2022 {
2023 if (rd->data_size == sizeof (*rec) + relay_count * sizeof (struct GNUNET_PeerIdentity))
2024 {
2025 relays = (struct GNUNET_PeerIdentity *) &rec[1];
2026 }
2027 else
2028 {
2029 relay_count = 0;
2030 GNUNET_break_op (0);
2031 }
2032 }
2033
2034 uint16_t app_id_size = strlen (gcls->app_id) + 1;
2035 uint16_t relay_size = relay_count * sizeof (*relays);
2036 uint16_t join_msg_size = 0;
2037 if (NULL != gcls->join_msg)
2038 join_msg_size = ntohs (gcls->join_msg->size);
2039 uint16_t greq_size = sizeof (struct GuestEnterRequest)
2040 + app_id_size + relay_size + join_msg_size;
2041 struct GuestEnterRequest *greq = GNUNET_malloc (greq_size);
2042 greq->header.size = htons (greq_size);
2043 greq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER);
2044 greq->ego_pub_key = gcls->ego_pub_key;
2045 greq->place_pub_key = rec->place_pub_key;
2046 greq->origin = rec->origin;
2047 greq->relay_count = rec->relay_count;
2048
2049 void *p = &greq[1];
2050 GNUNET_memcpy (p, gcls->app_id, app_id_size);
2051 p += app_id_size;
2052 GNUNET_memcpy (p, relays, relay_size);
2053 p += relay_size;
2054 GNUNET_memcpy (p, gcls->join_msg, join_msg_size);
2055
2056 client_guest_enter (c, greq);
2057
2058 GNUNET_free (gcls->app_id);
2059 if (NULL != gcls->password)
2060 GNUNET_free (gcls->password);
2061 if (NULL != gcls->join_msg)
2062 GNUNET_free (gcls->join_msg);
2063 GNUNET_free (gcls);
2064 GNUNET_free (greq);
2065}
2066
2067
2068static int
2069check_client_guest_enter_by_name (void *cls,
2070 const struct GuestEnterByNameRequest *greq)
2071{
2072 return GNUNET_OK;
2073}
2074
2075
2076/**
2077 * Handle a connecting client entering a place as guest using a GNS address.
2078 *
2079 * Look up GNS address and generate a GuestEnterRequest from that.
2080 */
2081static void
2082handle_client_guest_enter_by_name (void *cls,
2083 const struct GuestEnterByNameRequest *greq)
2084{
2085 struct Client *c = cls;
2086 struct GNUNET_SERVICE_Client *client = c->client;
2087
2088 struct GuestEnterByNameClosure *gcls = GNUNET_malloc (sizeof (*gcls));
2089 gcls->client = c;
2090 gcls->ego_pub_key = greq->ego_pub_key;
2091
2092 const char *p = (const char *) &greq[1];
2093 const char *app_id = NULL, *password = NULL, *gns_name = NULL;
2094 uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq);
2095 uint16_t offset = GNUNET_STRINGS_buffer_tokenize (p, remaining, 3,
2096 &app_id,
2097 &gns_name,
2098 &password);
2099 p += offset;
2100 remaining -= offset;
2101
2102 if (0 != offset && sizeof (*gcls->join_msg) <= remaining)
2103 {
2104 gcls->join_msg = GNUNET_copy_message ((struct GNUNET_MessageHeader *) p);
2105 remaining -= ntohs (gcls->join_msg->size);
2106 }
2107
2108 if (0 == offset || 0 != remaining)
2109 {
2110 if (NULL != gcls->join_msg)
2111 GNUNET_free (gcls->join_msg);
2112 GNUNET_free (gcls);
2113 GNUNET_break (0);
2114 GNUNET_SERVICE_client_drop (client);
2115 return;
2116 }
2117
2118 uint16_t app_id_size = strlen (app_id) + 1;
2119 gcls->app_id = GNUNET_malloc (app_id_size);
2120 GNUNET_memcpy (gcls->app_id, app_id, app_id_size);
2121
2122 uint16_t password_size = strlen (password);
2123 if (0 < password_size++)
2124 {
2125 gcls->password = GNUNET_malloc (password_size);
2126 GNUNET_memcpy (gcls->password, password, password_size);
2127 }
2128
2129 GNUNET_GNS_lookup (gns, gns_name,
2130 &greq->ego_pub_key,
2131 GNUNET_GNSRECORD_TYPE_PLACE,
2132 GNUNET_GNS_LO_DEFAULT,
2133 &gns_result_guest_enter, gcls);
2134 GNUNET_SERVICE_client_continue (client);
2135}
2136
2137
2138static int
2139check_client_app_connect (void *cls,
2140 const struct AppConnectRequest *creq)
2141{
2142 return GNUNET_OK;
2143}
2144
2145
2146/**
2147 * Handle application connection.
2148 */
2149static void
2150handle_client_app_connect (void *cls,
2151 const struct AppConnectRequest *creq)
2152{
2153 struct Client *c = cls;
2154 struct GNUNET_SERVICE_Client *client = c->client;
2155 ssize_t app_id_size = ntohs (creq->header.size) - sizeof (*creq);
2156 const char *app_id = NULL;
2157 uint16_t offset;
2158
2159 if (app_id_size < 0)
2160 {
2161 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2162 "AppConnectRequest has invalid size\n");
2163 GNUNET_break (0);
2164 GNUNET_SERVICE_client_drop (client);
2165 return;
2166 }
2167
2168 offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &creq[1],
2169 (size_t) app_id_size,
2170 1,
2171 &app_id);
2172 if (0 == offset || offset != app_id_size)
2173 {
2174 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2175 "AppConnectRequest contains invalid app ID\n");
2176 GNUNET_break (0);
2177 GNUNET_SERVICE_client_drop (client);
2178 return;
2179 }
2180
2181 struct GNUNET_HashCode app_id_hash;
2182 GNUNET_CRYPTO_hash (app_id, (size_t) app_id_size, &app_id_hash);
2183
2184 GNUNET_CONTAINER_multihashmap_iterate (egos, ego_entry, client);
2185 app_notify_ego_end (client);
2186
2187 struct GNUNET_CONTAINER_MultiHashMap *
2188 app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash);
2189 if (NULL != app_places)
2190 GNUNET_CONTAINER_multihashmap_iterate (app_places, app_place_entry_notify, client);
2191 app_notify_place_end (client);
2192
2193 struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
2194 cli->client = client;
2195 struct Application *app = GNUNET_CONTAINER_multihashmap_get (apps,
2196 &app_id_hash);
2197 if (NULL == app) {
2198 app = GNUNET_malloc (sizeof (*app));
2199 (void) GNUNET_CONTAINER_multihashmap_put (apps, &app_id_hash, app,
2200 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
2201 }
2202 GNUNET_CONTAINER_DLL_insert (app->clients_head, app->clients_tail, cli);
2203
2204 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2205 "%p Application %s connected.\n", app, app_id);
2206
2207 c->app_id = GNUNET_malloc ((size_t) app_id_size);
2208 GNUNET_memcpy (c->app_id, app_id, (size_t) app_id_size);
2209
2210 GNUNET_SERVICE_client_continue (client);
2211}
2212
2213
2214/**
2215 * Handle application detach request.
2216 */
2217static void
2218handle_client_app_detach (void *cls,
2219 const struct AppDetachRequest *req)
2220{
2221 struct Client *c = cls;
2222 struct GNUNET_SERVICE_Client *client = c->client;
2223
2224 int ret = app_place_remove (c->app_id, &req->ego_pub_key, &req->place_pub_key);
2225 client_send_result (client, req->op_id, ret, NULL, 0);
2226
2227 GNUNET_SERVICE_client_continue (client);
2228}
2229
2230
2231static void
2232place_leave_cb (void *cls)
2233{
2234 struct Place *plc = cls;
2235
2236 place_send_leave_ack (plc);
2237 (GNUNET_YES == plc->is_host)
2238 ? cleanup_host ((struct Host *) plc)
2239 : cleanup_guest ((struct Guest *) plc);
2240}
2241
2242
2243/**
2244 * Handle application leave request.
2245 */
2246static void
2247handle_client_place_leave (void *cls,
2248 const struct GNUNET_MessageHeader *msg)
2249{
2250 struct Client *c = cls;
2251 struct GNUNET_SERVICE_Client *client = c->client;
2252 struct Place *plc = c->place;
2253
2254 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2255 "got leave request from %s for place %s",
2256 plc->is_host? "host" : "slave",
2257 GNUNET_h2s (&plc->pub_key_hash));
2258 if (NULL == plc)
2259 {
2260 GNUNET_break (0);
2261 GNUNET_SERVICE_client_drop (client);
2262 return;
2263 }
2264
2265 if (GNUNET_YES != plc->is_disconnecting)
2266 {
2267 plc->is_disconnecting = GNUNET_YES;
2268 if (plc->is_host)
2269 {
2270 struct Host *host = plc->host;
2271 GNUNET_assert (NULL != host);
2272 GNUNET_PSYC_master_stop (host->master, GNUNET_NO, &place_leave_cb, plc);
2273 }
2274 else
2275 {
2276 struct Guest *guest = plc->guest;
2277 GNUNET_assert (NULL != guest);
2278 GNUNET_PSYC_slave_part (guest->slave, GNUNET_NO, &place_leave_cb, plc);
2279 }
2280 }
2281 else
2282 {
2283 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2284 "got leave request but place is already leaving\n");
2285 }
2286 GNUNET_SERVICE_client_continue (client);
2287}
2288
2289
2290struct JoinDecisionClosure
2291{
2292 int32_t is_admitted;
2293 struct GNUNET_PSYC_Message *msg;
2294};
2295
2296
2297/**
2298 * Iterator callback for responding to join requests.
2299 */
2300static int
2301psyc_send_join_decision (void *cls, const struct GNUNET_HashCode *pub_key_hash,
2302 void *value)
2303{
2304 struct JoinDecisionClosure *jcls = cls;
2305 struct GNUNET_PSYC_JoinHandle *jh = value;
2306 // FIXME: add relays
2307 GNUNET_PSYC_join_decision (jh, jcls->is_admitted, 0, NULL, jcls->msg);
2308 return GNUNET_YES;
2309}
2310
2311
2312static int
2313check_client_join_decision (void *cls,
2314 const struct GNUNET_PSYC_JoinDecisionMessage *dcsn)
2315{
2316 return GNUNET_OK;
2317}
2318
2319
2320/**
2321 * Handle an entry decision from a host client.
2322 */
2323static void
2324handle_client_join_decision (void *cls,
2325 const struct GNUNET_PSYC_JoinDecisionMessage *dcsn)
2326{
2327 struct Client *c = cls;
2328 struct GNUNET_SERVICE_Client *client = c->client;
2329 struct Place *plc = c->place;
2330 if (NULL == plc || GNUNET_YES != plc->is_host)
2331 {
2332 GNUNET_break (0);
2333 GNUNET_SERVICE_client_drop (client);
2334 return;
2335 }
2336 struct Host *hst = plc->host;
2337
2338 struct JoinDecisionClosure jcls;
2339 jcls.is_admitted = ntohl (dcsn->is_admitted);
2340 jcls.msg
2341 = (sizeof (*dcsn) + sizeof (*jcls.msg) <= ntohs (dcsn->header.size))
2342 ? (struct GNUNET_PSYC_Message *) &dcsn[1]
2343 : NULL;
2344
2345 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2346 "jcls.msg = %p\n",
2347 jcls.msg);
2348 struct GNUNET_HashCode slave_pub_hash;
2349 GNUNET_CRYPTO_hash (&dcsn->slave_pub_key, sizeof (dcsn->slave_pub_key),
2350 &slave_pub_hash);
2351
2352 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2353 "%p Got join decision (%d) from client for place %s..\n",
2354 hst, jcls.is_admitted, GNUNET_h2s (&plc->pub_key_hash));
2355 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2356 "%p ..and slave %s.\n",
2357 hst, GNUNET_h2s (&slave_pub_hash));
2358
2359 GNUNET_CONTAINER_multihashmap_get_multiple (hst->join_reqs, &slave_pub_hash,
2360 &psyc_send_join_decision, &jcls);
2361 GNUNET_CONTAINER_multihashmap_remove_all (hst->join_reqs, &slave_pub_hash);
2362
2363 GNUNET_SERVICE_client_continue (client);
2364}
2365
2366
2367/**
2368 * Send acknowledgement to a client.
2369 *
2370 * Sent after a message fragment has been passed on to multicast.
2371 *
2372 * @param plc The place struct for the client.
2373 */
2374static void
2375send_message_ack (struct Place *plc, struct GNUNET_SERVICE_Client *client)
2376{
2377 struct GNUNET_MQ_Envelope *env;
2378
2379 env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK);
2380 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
2381 env);
2382}
2383
2384
2385/**
2386 * Proceed to the next message part in the transmission queue.
2387 *
2388 * @param plc
2389 * Place where the transmission is going on.
2390 * @param tmit_msg
2391 * Currently transmitted message.
2392 * @param tmit_frag
2393 * Currently transmitted message fragment.
2394 *
2395 * @return @a tmit_frag, or NULL if reached the end of fragment.
2396 */
2397static struct FragmentTransmitQueue *
2398psyc_transmit_queue_next_part (struct Place *plc,
2399 struct MessageTransmitQueue *tmit_msg,
2400 struct FragmentTransmitQueue *tmit_frag)
2401{
2402 uint16_t psize = ntohs (tmit_frag->next_part->size);
2403 if ((char *) tmit_frag->next_part + psize - ((char *) &tmit_frag[1])
2404 < tmit_frag->size)
2405 {
2406 tmit_frag->next_part
2407 = (struct GNUNET_MessageHeader *) ((char *) tmit_frag->next_part + psize);
2408 }
2409 else /* Reached end of current fragment. */
2410 {
2411 if (NULL != tmit_frag->client)
2412 send_message_ack (plc, tmit_frag->client);
2413 GNUNET_CONTAINER_DLL_remove (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag);
2414 GNUNET_free (tmit_frag);
2415 tmit_frag = NULL;
2416 }
2417 return tmit_frag;
2418}
2419
2420
2421/**
2422 * Proceed to next message in transmission queue.
2423 *
2424 * @param plc
2425 * Place where the transmission is going on.
2426 * @param tmit_msg
2427 * Currently transmitted message.
2428 *
2429 * @return The next message in queue, or NULL if queue is empty.
2430 */
2431static struct MessageTransmitQueue *
2432psyc_transmit_queue_next_msg (struct Place *plc,
2433 struct MessageTransmitQueue *tmit_msg)
2434{
2435 GNUNET_CONTAINER_DLL_remove (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg);
2436 GNUNET_free (tmit_msg);
2437 return plc->tmit_msgs_head;
2438}
2439
2440
2441/**
2442 * Callback for data transmission to PSYC.
2443 */
2444static int
2445psyc_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
2446{
2447 struct Place *plc = cls;
2448 struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
2449 GNUNET_assert (NULL != tmit_msg);
2450 struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
2451 if (NULL == tmit_frag)
2452 { /* Rest of the message have not arrived yet, pause transmission */
2453 *data_size = 0;
2454 return GNUNET_NO;
2455 }
2456 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
2457 if (NULL == pmsg)
2458 {
2459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2460 "%p psyc_transmit_notify_data: nothing to send.\n", plc);
2461 *data_size = 0;
2462 return GNUNET_NO;
2463 }
2464
2465 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2466 "%p psyc_transmit_notify_data()\n", plc);
2467 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
2468
2469 uint16_t ptype = ntohs (pmsg->type);
2470 uint16_t pdata_size = ntohs (pmsg->size) - sizeof (*pmsg);
2471 int ret;
2472
2473 switch (ptype)
2474 {
2475 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
2476 if (*data_size < pdata_size)
2477 {
2478 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2479 "%p psyc_transmit_notify_data: buffer size too small for data.\n", plc);
2480 *data_size = 0;
2481 return GNUNET_NO;
2482 }
2483 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2484 "%p psyc_transmit_notify_data: sending %u bytes.\n",
2485 plc, pdata_size);
2486
2487 *data_size = pdata_size;
2488 GNUNET_memcpy (data, &pmsg[1], *data_size);
2489 ret = GNUNET_NO;
2490 break;
2491
2492 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
2493 *data_size = 0;
2494 ret = GNUNET_YES;
2495 break;
2496
2497 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
2498 *data_size = 0;
2499 ret = GNUNET_SYSERR;
2500 break;
2501
2502 default:
2503 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2504 "%p psyc_transmit_notify_data: unexpected message part of type %u.\n",
2505 plc, ptype);
2506 ret = GNUNET_SYSERR;
2507 }
2508
2509 if (GNUNET_SYSERR == ret && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL != ptype)
2510 {
2511 *data_size = 0;
2512 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
2513 GNUNET_SERVICE_client_drop (tmit_frag->client);
2514 GNUNET_SCHEDULER_add_now (&cleanup_place, plc);
2515 return ret;
2516 }
2517 else
2518 {
2519 tmit_frag = psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
2520 if (NULL != tmit_frag)
2521 {
2522 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
2523 ptype = ntohs (pmsg->type);
2524 switch (ptype)
2525 {
2526 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
2527 ret = GNUNET_YES;
2528 break;
2529 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
2530 ret = GNUNET_SYSERR;
2531 break;
2532 }
2533 switch (ptype)
2534 {
2535 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
2536 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
2537 tmit_frag = psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
2538 }
2539 }
2540
2541 if (NULL == tmit_msg->frags_head
2542 && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
2543 { /* Reached end of current message. */
2544 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
2545 }
2546 }
2547
2548 if (ret != GNUNET_NO)
2549 {
2550 if (NULL != tmit_msg)
2551 {
2552 psyc_transmit_message (plc);
2553 }
2554 /* FIXME: handle partial message (when still in_transmit) */
2555 }
2556 return ret;
2557}
2558
2559
2560/**
2561 * Callback for modifier transmission to PSYC.
2562 */
2563static int
2564psyc_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
2565 uint8_t *oper, uint32_t *full_value_size)
2566{
2567 struct Place *plc = cls;
2568 struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
2569 GNUNET_assert (NULL != tmit_msg);
2570 struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
2571 if (NULL == tmit_frag)
2572 { /* Rest of the message have not arrived yet, pause transmission */
2573 *data_size = 0;
2574 return GNUNET_NO;
2575 }
2576 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
2577 if (NULL == pmsg)
2578 {
2579 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2580 "%p psyc_transmit_notify_mod: nothing to send.\n", plc);
2581 *data_size = 0;
2582 return GNUNET_NO;
2583 }
2584
2585 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2586 "%p psyc_transmit_notify_mod()\n", plc);
2587 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
2588
2589 uint16_t ptype = ntohs (pmsg->type);
2590 int ret;
2591
2592 switch (ptype)
2593 {
2594 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
2595 {
2596 if (NULL == oper)
2597 {
2598 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2599 "%p psyc_transmit_notify_mod: oper is NULL.\n", plc);
2600 ret = GNUNET_SYSERR;
2601 break;
2602 }
2603 struct GNUNET_PSYC_MessageModifier *
2604 pmod = (struct GNUNET_PSYC_MessageModifier *) tmit_frag->next_part;
2605 uint16_t mod_size = ntohs (pmod->header.size) - sizeof (*pmod);
2606
2607 if (*data_size < mod_size)
2608 {
2609 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2610 "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc);
2611 *data_size = 0;
2612 return GNUNET_NO;
2613 }
2614
2615 *full_value_size = ntohl (pmod->value_size);
2616 *oper = pmod->oper;
2617 *data_size = mod_size;
2618 GNUNET_memcpy (data, &pmod[1], mod_size);
2619 ret = GNUNET_NO;
2620 break;
2621 }
2622
2623 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
2624 {
2625 if (NULL != oper)
2626 {
2627 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2628 "%p psyc_transmit_notify_mod: oper is not NULL.\n", plc);
2629 ret = GNUNET_SYSERR;
2630 break;
2631 }
2632 uint16_t mod_size = ntohs (pmsg->size) - sizeof (*pmsg);
2633 if (*data_size < mod_size)
2634 {
2635 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2636 "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc);
2637 *data_size = 0;
2638 return GNUNET_NO;
2639 }
2640 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2641 "%p psyc_transmit_notify_mod: sending %u bytes.\n", plc, mod_size);
2642
2643 *data_size = mod_size;
2644 GNUNET_memcpy (data, &pmsg[1], *data_size);
2645 ret = GNUNET_NO;
2646 break;
2647 }
2648
2649 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
2650 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
2651 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
2652 *data_size = 0;
2653 ret = GNUNET_YES;
2654 break;
2655
2656 default:
2657 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2658 "%p psyc_transmit_notify_mod: unexpected message part of type %u.\n",
2659 plc, ptype);
2660 ret = GNUNET_SYSERR;
2661 }
2662
2663 if (GNUNET_SYSERR == ret)
2664 {
2665 *data_size = 0;
2666 ret = GNUNET_SYSERR;
2667 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
2668 GNUNET_SERVICE_client_drop (tmit_frag->client);
2669 GNUNET_SCHEDULER_add_now (&cleanup_place, plc);
2670 }
2671 else
2672 {
2673 if (GNUNET_YES != ret)
2674 psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
2675
2676 if (NULL == tmit_msg->frags_head
2677 && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
2678 { /* Reached end of current message. */
2679 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
2680 }
2681 }
2682 return ret;
2683}
2684
2685/**
2686 * Callback for data transmission from a host to PSYC.
2687 */
2688static int
2689host_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
2690{
2691 int ret = psyc_transmit_notify_data (cls, data_size, data);
2692
2693 if (GNUNET_NO != ret)
2694 {
2695 struct Host *hst = cls;
2696 hst->tmit_handle = NULL;
2697 }
2698 return ret;
2699}
2700
2701
2702/**
2703 * Callback for the transmit functions of multicast.
2704 */
2705static int
2706guest_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
2707{
2708 int ret = psyc_transmit_notify_data (cls, data_size, data);
2709
2710 if (GNUNET_NO != ret)
2711 {
2712 struct Guest *gst = cls;
2713 gst->tmit_handle = NULL;
2714 }
2715 return ret;
2716}
2717
2718
2719/**
2720 * Callback for modifier transmission from a host to PSYC.
2721 */
2722static int
2723host_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
2724 uint8_t *oper, uint32_t *full_value_size)
2725{
2726 int ret = psyc_transmit_notify_mod (cls, data_size, data,
2727 oper, full_value_size);
2728 if (GNUNET_SYSERR == ret)
2729 {
2730 struct Host *hst = cls;
2731 hst->tmit_handle = NULL;
2732 }
2733 return ret;
2734}
2735
2736
2737/**
2738 * Callback for modifier transmission from a guest to PSYC.
2739 */
2740static int
2741guest_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
2742 uint8_t *oper, uint32_t *full_value_size)
2743{
2744 int ret = psyc_transmit_notify_mod (cls, data_size, data,
2745 oper, full_value_size);
2746 if (GNUNET_SYSERR == ret)
2747 {
2748 struct Guest *gst = cls;
2749 gst->tmit_handle = NULL;
2750 }
2751 return ret;
2752}
2753
2754
2755/**
2756 * Get method part of next message from transmission queue.
2757 *
2758 * @param plc
2759 * Place
2760 *
2761 * @return #GNUNET_OK on success
2762 * #GNUNET_NO if there are no more messages in queue.
2763 * #GNUNET_SYSERR if the next message is malformed.
2764 */
2765static struct GNUNET_PSYC_MessageMethod *
2766psyc_transmit_queue_next_method (struct Place *plc)
2767{
2768 struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
2769 if (NULL == tmit_msg)
2770 return GNUNET_NO;
2771
2772 struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
2773 if (NULL == tmit_frag)
2774 {
2775 GNUNET_break (0);
2776 return GNUNET_NO;
2777 }
2778
2779 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
2780 if (NULL == pmsg
2781 || GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD != ntohs (pmsg->type))
2782 {
2783 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2784 "%p psyc_transmit_queue_next_method: unexpected message part of type %u.\n",
2785 plc, NULL != pmsg ? ntohs (pmsg->type) : 0);
2786 GNUNET_break (0);
2787 return NULL;
2788 }
2789
2790 uint16_t psize = ntohs (pmsg->size);
2791 struct GNUNET_PSYC_MessageMethod *
2792 pmeth = (struct GNUNET_PSYC_MessageMethod *) GNUNET_copy_message (pmsg);
2793
2794 if (psize < sizeof (*pmeth) + 1 || '\0' != *((char *) pmeth + psize - 1))
2795 {
2796 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2797 "%p psyc_transmit_queue_next_method: invalid method name.\n",
2798 plc);
2799 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2800 "%zu <= %u || NUL != %u\n",
2801 sizeof (*pmeth), psize, *((char *) pmeth + psize - 1));
2802 GNUNET_break (0);
2803 GNUNET_free (pmeth);
2804 return NULL;
2805 }
2806
2807 psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
2808 return pmeth;
2809}
2810
2811
2812/**
2813 * Transmit the next message in queue from the host to the PSYC channel.
2814 */
2815static int
2816psyc_master_transmit_message (struct Host *hst)
2817{
2818 struct Place *plc = &hst->place;
2819
2820 if (NULL == hst->tmit_handle)
2821 {
2822 struct GNUNET_PSYC_MessageMethod *
2823 pmeth = psyc_transmit_queue_next_method (plc);
2824 if (NULL == pmeth)
2825 return GNUNET_SYSERR;
2826
2827 hst->tmit_handle = (void *) &hst->tmit_handle;
2828 struct GNUNET_PSYC_MasterTransmitHandle *
2829 tmit_handle = GNUNET_PSYC_master_transmit (hst->master, (const char *) &pmeth[1],
2830 &host_transmit_notify_mod,
2831 &host_transmit_notify_data, hst,
2832 pmeth->flags);
2833 if (NULL != hst->tmit_handle)
2834 hst->tmit_handle = tmit_handle;
2835 GNUNET_free (pmeth);
2836 }
2837 else
2838 {
2839 GNUNET_PSYC_master_transmit_resume (hst->tmit_handle);
2840 }
2841 return GNUNET_OK;
2842}
2843
2844
2845/**
2846 * Transmit the next message in queue from a guest to the PSYC channel.
2847 */
2848static int
2849psyc_slave_transmit_message (struct Guest *gst)
2850{
2851 struct Place *plc = &gst->place;
2852
2853 if (NULL == gst->tmit_handle)
2854 {
2855 struct GNUNET_PSYC_MessageMethod *
2856 pmeth = psyc_transmit_queue_next_method (plc);
2857 if (NULL == pmeth)
2858 return GNUNET_SYSERR;
2859
2860 gst->tmit_handle = (void *) &gst->tmit_handle;
2861 struct GNUNET_PSYC_SlaveTransmitHandle *
2862 tmit_handle = GNUNET_PSYC_slave_transmit (gst->slave, (const char *) &pmeth[1],
2863 &guest_transmit_notify_mod,
2864 &guest_transmit_notify_data, gst,
2865 pmeth->flags);
2866 if (NULL != gst->tmit_handle)
2867 gst->tmit_handle = tmit_handle;
2868 GNUNET_free (pmeth);
2869 }
2870 else
2871 {
2872 GNUNET_PSYC_slave_transmit_resume (gst->tmit_handle);
2873 }
2874 return GNUNET_OK;
2875}
2876
2877
2878/**
2879 * Transmit a message to PSYC.
2880 */
2881static int
2882psyc_transmit_message (struct Place *plc)
2883{
2884 return
2885 (plc->is_host)
2886 ? psyc_master_transmit_message ((struct Host *) plc)
2887 : psyc_slave_transmit_message ((struct Guest *) plc);
2888}
2889
2890
2891/**
2892 * Queue message parts for sending to PSYC.
2893 *
2894 * @param plc Place to send to.
2895 * @param client Client the message originates from.
2896 * @param data_size Size of @a data.
2897 * @param data Concatenated message parts.
2898 * @param first_ptype First message part type in @a data.
2899 * @param last_ptype Last message part type in @a data.
2900 */
2901static struct MessageTransmitQueue *
2902psyc_transmit_queue_message (struct Place *plc,
2903 struct GNUNET_SERVICE_Client *client,
2904 size_t data_size,
2905 const void *data,
2906 uint16_t first_ptype, uint16_t last_ptype,
2907 struct MessageTransmitQueue *tmit_msg)
2908{
2909 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == first_ptype)
2910 {
2911 tmit_msg = GNUNET_malloc (sizeof (*tmit_msg));
2912 GNUNET_CONTAINER_DLL_insert_tail (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg);
2913 }
2914 else if (NULL == tmit_msg)
2915 {
2916 return NULL;
2917 }
2918
2919 struct FragmentTransmitQueue *
2920 tmit_frag = GNUNET_malloc (sizeof (*tmit_frag) + data_size);
2921 GNUNET_memcpy (&tmit_frag[1], data, data_size);
2922 tmit_frag->next_part = (struct GNUNET_MessageHeader *) &tmit_frag[1];
2923 tmit_frag->client = client;
2924 tmit_frag->size = data_size;
2925
2926 GNUNET_CONTAINER_DLL_insert_tail (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag);
2927 tmit_msg->client = client;
2928 return tmit_msg;
2929}
2930
2931
2932///**
2933// * Cancel transmission of current message to PSYC.
2934// *
2935// * @param plc Place to send to.
2936// * @param client Client the message originates from.
2937// */
2938//static void
2939//psyc_transmit_cancel (struct Place *plc, struct GNUNET_SERVICE_Client *client)
2940//{
2941// uint16_t type = GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL;
2942//
2943// struct GNUNET_MessageHeader msg;
2944// msg.size = htons (sizeof (msg));
2945// msg.type = htons (type);
2946//
2947// psyc_transmit_queue_message (plc, client, sizeof (msg), &msg, type, type, NULL);
2948// psyc_transmit_message (plc);
2949//
2950// /* FIXME: cleanup */
2951//}
2952
2953
2954static int
2955check_client_psyc_message (void *cls,
2956 const struct GNUNET_MessageHeader *msg)
2957{
2958 return GNUNET_OK;
2959}
2960
2961
2962/**
2963 * Handle an incoming message from a client, to be transmitted to the place.
2964 */
2965static void
2966handle_client_psyc_message (void *cls,
2967 const struct GNUNET_MessageHeader *msg)
2968{
2969 struct Client *c = cls;
2970 struct GNUNET_SERVICE_Client *client = c->client;
2971 struct Place *plc = c->place;
2972 int ret;
2973
2974 if (NULL == plc)
2975 {
2976 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2977 "received PSYC message for non-existing client %p\n",
2978 client);
2979 GNUNET_break (0);
2980 GNUNET_SERVICE_client_drop (client);
2981 return;
2982 }
2983 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2984 "%p Received message of type %d from client.\n", plc, ntohs (msg->type));
2985 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, msg);
2986
2987 if (GNUNET_YES != plc->is_ready)
2988 {
2989 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2990 "%p Place is not ready yet, disconnecting client.\n", plc);
2991 GNUNET_break (0);
2992 GNUNET_SERVICE_client_drop (client);
2993 return;
2994 }
2995
2996 uint16_t size = ntohs (msg->size);
2997 uint16_t psize = size - sizeof (*msg);
2998 if (psize < sizeof (struct GNUNET_MessageHeader)
2999 || GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < psize)
3000 {
3001 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3002 "%p Received message with invalid payload size (%u) from client.\n",
3003 plc, psize);
3004 GNUNET_break (0);
3005 GNUNET_SERVICE_client_drop (client);
3006 return;
3007 }
3008
3009 uint16_t first_ptype = 0;
3010 uint16_t last_ptype = 0;
3011 if (GNUNET_SYSERR ==
3012 GNUNET_PSYC_receive_check_parts (psize, (const char *) &msg[1],
3013 &first_ptype, &last_ptype))
3014 {
3015 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3016 "%p Received invalid message part from client.\n", plc);
3017 GNUNET_break (0);
3018 GNUNET_SERVICE_client_drop (client);
3019 return;
3020 }
3021 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3022 "%p Received message with first part type %u and last part type %u.\n",
3023 plc, first_ptype, last_ptype);
3024
3025 c->tmit_msg
3026 = psyc_transmit_queue_message (plc, client, psize, &msg[1],
3027 first_ptype, last_ptype, c->tmit_msg);
3028 if (NULL != c->tmit_msg)
3029 {
3030 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= last_ptype)
3031 c->tmit_msg = NULL;
3032 ret = psyc_transmit_message (plc);
3033 }
3034 else
3035 {
3036 ret = GNUNET_SYSERR;
3037 }
3038 if (GNUNET_OK != ret)
3039 {
3040 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3041 "%p Received invalid message part from client.\n", plc);
3042 GNUNET_break (0);
3043 GNUNET_SERVICE_client_drop (client);
3044 return;
3045 }
3046 GNUNET_SERVICE_client_continue (client);
3047}
3048
3049
3050/**
3051 * A historic message arrived from PSYC.
3052 */
3053static void
3054psyc_recv_history_message (void *cls, const struct GNUNET_PSYC_MessageHeader *msg)
3055{
3056 struct OperationClosure *opcls = cls;
3057 struct Client *c = opcls->client;
3058 struct Place *plc = c->place;
3059
3060 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3061 "%p Received historic message #%" PRId64 " (flags: %x)\n",
3062 plc, GNUNET_ntohll (msg->message_id), ntohl (msg->flags));
3063
3064 uint16_t size = ntohs (msg->header.size);
3065
3066 struct GNUNET_OperationResultMessage *
3067 res = GNUNET_malloc (sizeof (*res) + size);
3068 res->header.size = htons (sizeof (*res) + size);
3069 res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT);
3070 res->op_id = opcls->op_id;
3071 res->result_code = GNUNET_htonll (GNUNET_OK);
3072
3073 GNUNET_memcpy (&res[1], msg, size);
3074
3075 /** @todo FIXME: send only to requesting client */
3076 place_send_msg (plc, GNUNET_MQ_msg_copy (&res->header));
3077
3078 GNUNET_free (res);
3079}
3080
3081
3082/**
3083 * Result of message history replay from PSYC.
3084 */
3085static void
3086psyc_recv_history_result (void *cls, int64_t result,
3087 const void *err_msg, uint16_t err_msg_size)
3088{
3089 struct OperationClosure *opcls = cls;
3090 struct Client *c = opcls->client;
3091 struct Place *plc = c->place;
3092
3093 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3094 "%p History replay #%" PRIu64 ": "
3095 "PSYCstore returned %" PRId64 " (%.*s)\n",
3096 plc, GNUNET_ntohll (opcls->op_id), result,
3097 err_msg_size, (const char *) err_msg);
3098
3099 // FIXME: place might have been destroyed
3100 client_send_result (c->client, opcls->op_id, result, err_msg, err_msg_size);
3101}
3102
3103
3104static int
3105check_client_history_replay (void *cls,
3106 const struct GNUNET_PSYC_HistoryRequestMessage *req)
3107{
3108 return GNUNET_OK;
3109}
3110
3111
3112/**
3113 * Client requests channel history.
3114 */
3115static void
3116handle_client_history_replay (void *cls,
3117 const struct GNUNET_PSYC_HistoryRequestMessage *req)
3118{
3119 struct Client *c = cls;
3120 struct GNUNET_SERVICE_Client *client = c->client;
3121 struct Place *plc = c->place;
3122 if (NULL == plc)
3123 {
3124 GNUNET_break (0);
3125 GNUNET_SERVICE_client_drop (client);
3126 return;
3127 }
3128
3129 uint16_t size = ntohs (req->header.size);
3130 const char *method_prefix = (const char *) &req[1];
3131
3132 if (size < sizeof (*req) + 1
3133 || '\0' != method_prefix[size - sizeof (*req) - 1])
3134 {
3135 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3136 "%p History replay #%" PRIu64 ": "
3137 "invalid method prefix. size: %u < %zu?\n",
3138 plc, GNUNET_ntohll (req->op_id), size, sizeof (*req) + 1);
3139 GNUNET_break (0);
3140 GNUNET_SERVICE_client_drop (client);
3141 return;
3142 }
3143
3144 struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls));
3145 opcls->client = c;
3146 opcls->op_id = req->op_id;
3147 opcls->flags = ntohl (req->flags);
3148
3149 if (0 == req->message_limit)
3150 GNUNET_PSYC_channel_history_replay (plc->channel,
3151 GNUNET_ntohll (req->start_message_id),
3152 GNUNET_ntohll (req->end_message_id),
3153 method_prefix, opcls->flags,
3154 psyc_recv_history_message, NULL,
3155 psyc_recv_history_result, opcls);
3156 else
3157 GNUNET_PSYC_channel_history_replay_latest (plc->channel,
3158 GNUNET_ntohll (req->message_limit),
3159 method_prefix, opcls->flags,
3160 psyc_recv_history_message, NULL,
3161 psyc_recv_history_result, opcls);
3162
3163 GNUNET_SERVICE_client_continue (client);
3164}
3165
3166
3167/**
3168 * A state variable part arrived from PSYC.
3169 */
3170void
3171psyc_recv_state_var (void *cls,
3172 const struct GNUNET_MessageHeader *mod,
3173 const char *name,
3174 const void *value,
3175 uint32_t value_size,
3176 uint32_t full_value_size)
3177{
3178 struct GNUNET_OperationResultMessage *result_msg;
3179 struct GNUNET_MQ_Envelope *env;
3180 struct OperationClosure *opcls = cls;
3181 struct Client *c = opcls->client;
3182 struct Place *plc = c->place;
3183 uint16_t size = ntohs (mod->size);
3184
3185 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3186 "%p Received state variable %s from PSYC\n",
3187 plc, name);
3188 env = GNUNET_MQ_msg_extra (result_msg,
3189 size,
3190 GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT);
3191 result_msg->op_id = opcls->op_id;
3192 result_msg->result_code = GNUNET_htonll (GNUNET_OK);
3193 GNUNET_memcpy (&result_msg[1], mod, size);
3194 /** @todo FIXME: send only to requesting client */
3195 place_send_msg (plc, env);
3196}
3197
3198
3199/**
3200 * Result of retrieving state variable from PSYC.
3201 */
3202static void
3203psyc_recv_state_result (void *cls, int64_t result,
3204 const void *err_msg, uint16_t err_msg_size)
3205{
3206 struct OperationClosure *opcls = cls;
3207 struct Client *c = opcls->client;
3208 struct Place *plc = c->place;
3209
3210 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3211 "%p State get #%" PRIu64 ": "
3212 "PSYCstore returned %" PRId64 " (%.*s)\n",
3213 plc, GNUNET_ntohll (opcls->op_id), result,
3214 err_msg_size, (const char *) err_msg);
3215
3216 // FIXME: place might have been destroyed
3217 client_send_result (c->client, opcls->op_id, result, err_msg, err_msg_size);
3218}
3219
3220
3221static int
3222check_client_state_get (void *cls,
3223 const struct GNUNET_PSYC_StateRequestMessage *req)
3224{
3225 return GNUNET_OK;
3226}
3227
3228
3229/**
3230 * Client requests channel history.
3231 */
3232static void
3233handle_client_state_get (void *cls,
3234 const struct GNUNET_PSYC_StateRequestMessage *req)
3235{
3236 struct Client *c = cls;
3237 struct GNUNET_SERVICE_Client *client = c->client;
3238 struct Place *plc = c->place;
3239 if (NULL == plc)
3240 {
3241 GNUNET_break (0);
3242 GNUNET_SERVICE_client_drop (client);
3243 return;
3244 }
3245
3246 uint16_t size = ntohs (req->header.size);
3247 const char *name = (const char *) &req[1];
3248
3249 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3250 "%p State get #%" PRIu64 ": %s\n",
3251 plc, GNUNET_ntohll (req->op_id), name);
3252
3253 if (size < sizeof (*req) + 1
3254 || '\0' != name[size - sizeof (*req) - 1])
3255 {
3256 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3257 "%p State get #%" PRIu64 ": "
3258 "invalid name. size: %u < %zu?\n",
3259 plc, GNUNET_ntohll (req->op_id), size, sizeof (*req) + 1);
3260 GNUNET_break (0);
3261 GNUNET_SERVICE_client_drop (client);
3262 return;
3263 }
3264
3265 struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls));
3266 opcls->client = c;
3267 opcls->op_id = req->op_id;
3268
3269 switch (ntohs (req->header.type))
3270 {
3271 case GNUNET_MESSAGE_TYPE_PSYC_STATE_GET:
3272 GNUNET_PSYC_channel_state_get (plc->channel, name,
3273 psyc_recv_state_var,
3274 psyc_recv_state_result, opcls);
3275 break;
3276
3277 case GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX:
3278 GNUNET_PSYC_channel_state_get_prefix (plc->channel, name,
3279 psyc_recv_state_var,
3280 psyc_recv_state_result, opcls);
3281 break;
3282
3283 default:
3284 GNUNET_assert (0);
3285 }
3286
3287 GNUNET_SERVICE_client_continue (client);
3288}
3289
3290
3291#define check_client_state_get_prefix check_client_state_get
3292#define handle_client_state_get_prefix handle_client_state_get
3293
3294
3295static void
3296namestore_recv_records_store_result (void *cls, int32_t result,
3297 const char *err_msg)
3298{
3299 struct OperationClosure *opcls = cls;
3300 struct Client *c = opcls->client;
3301
3302 // FIXME: client might have been disconnected
3303 client_send_result (c->client, opcls->op_id, result, err_msg,
3304 (NULL != err_msg) ? strlen (err_msg) : 0);
3305 GNUNET_free (opcls);
3306}
3307
3308
3309static int
3310check_client_zone_add_place (void *cls,
3311 const struct ZoneAddPlaceRequest *preq)
3312{
3313 return GNUNET_OK;
3314}
3315
3316
3317/**
3318 * Handle request to add PLACE record to GNS zone.
3319 */
3320static void
3321handle_client_zone_add_place (void *cls,
3322 const struct ZoneAddPlaceRequest *preq)
3323{
3324 struct Client *c = cls;
3325 struct GNUNET_SERVICE_Client *client = c->client;
3326
3327 uint16_t remaining = ntohs (preq->header.size) - sizeof (*preq);
3328 const char *p = (const char *) &preq[1];
3329 const char *name = NULL, *password = NULL;
3330 uint16_t offset = GNUNET_STRINGS_buffer_tokenize (p, remaining, 2,
3331 &name, &password);
3332 remaining -= offset;
3333 p += offset;
3334 const struct GNUNET_PeerIdentity *
3335 relays = (const struct GNUNET_PeerIdentity *) p;
3336 uint16_t relay_size = ntohl (preq->relay_count) * sizeof (*relays);
3337
3338 if (0 == offset || remaining != relay_size)
3339 {
3340 GNUNET_break (0);
3341 client_send_result (client, preq->op_id, GNUNET_SYSERR, NULL, 0);
3342 GNUNET_SERVICE_client_drop (client);
3343 return;
3344 }
3345
3346 struct GNUNET_GNSRECORD_Data rd = { };
3347 rd.record_type = GNUNET_GNSRECORD_TYPE_PLACE;
3348 rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
3349 rd.expiration_time = GNUNET_ntohll (preq->expiration_time);
3350
3351 struct GNUNET_GNSRECORD_PlaceData *
3352 rec = GNUNET_malloc (sizeof (*rec) + relay_size);
3353 rec->place_pub_key = preq->place_pub_key;
3354 rec->origin = this_peer;
3355 rec->relay_count = preq->relay_count;
3356 GNUNET_memcpy (&rec[1], relays, relay_size);
3357
3358 rd.data = rec;
3359 rd.data_size = sizeof (*rec) + relay_size;
3360
3361 struct GNUNET_HashCode ego_pub_hash;
3362 GNUNET_CRYPTO_hash (&preq->ego_pub_key, sizeof (preq->ego_pub_key), &ego_pub_hash);
3363 struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
3364 if (NULL == ego)
3365 {
3366 client_send_result (client, preq->op_id, GNUNET_SYSERR, NULL, 0);
3367 }
3368 else
3369 {
3370 struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls));
3371 opcls->client = c;
3372 opcls->op_id = preq->op_id;
3373 GNUNET_NAMESTORE_records_store (namestore, &ego->key,
3374 name, 1, &rd,
3375 namestore_recv_records_store_result, opcls);
3376 /** @todo refresh stored records later */
3377 }
3378 GNUNET_SERVICE_client_continue (client);
3379}
3380
3381
3382static int
3383check_client_zone_add_nym (void *cls,
3384 const struct ZoneAddNymRequest *nreq)
3385{
3386 return GNUNET_OK;
3387}
3388
3389
3390/**
3391 * Handle request to add PLACE record to GNS zone.
3392 */
3393static void
3394handle_client_zone_add_nym (void *cls,
3395 const struct ZoneAddNymRequest *nreq)
3396{
3397 struct Client *c = cls;
3398 struct GNUNET_SERVICE_Client *client = c->client;
3399
3400 uint16_t name_size = ntohs (nreq->header.size) - sizeof (*nreq);
3401 const char *name = NULL;
3402 uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &nreq[1],
3403 name_size, 1, &name);
3404 if (0 == offset || offset != name_size)
3405 {
3406 GNUNET_break (0);
3407 client_send_result (client, nreq->op_id, GNUNET_SYSERR, NULL, 0);
3408 GNUNET_SERVICE_client_continue (client);
3409 return;
3410 }
3411
3412 struct GNUNET_GNSRECORD_Data rd = { };
3413 rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
3414 rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
3415 rd.expiration_time = GNUNET_ntohll (nreq->expiration_time);
3416 rd.data = &nreq->nym_pub_key;
3417 rd.data_size = sizeof (nreq->nym_pub_key);
3418
3419 struct GNUNET_HashCode ego_pub_hash;
3420 GNUNET_CRYPTO_hash (&nreq->ego_pub_key, sizeof (nreq->ego_pub_key), &ego_pub_hash);
3421 struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
3422 if (NULL == ego)
3423 {
3424 client_send_result (client, nreq->op_id, GNUNET_SYSERR, NULL, 0);
3425 }
3426 else
3427 {
3428 struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls));
3429 opcls->client = c;
3430 opcls->op_id = nreq->op_id;
3431 GNUNET_NAMESTORE_records_store (namestore, &ego->key,
3432 name, 1, &rd,
3433 namestore_recv_records_store_result, opcls);
3434 /** @todo refresh stored records later */
3435 }
3436 GNUNET_SERVICE_client_continue (client);
3437}
3438
3439
3440const char *
3441path_basename (const char *path)
3442{
3443 const char *basename = strrchr (path, DIR_SEPARATOR);
3444 if (NULL != basename)
3445 basename++;
3446
3447 if (NULL == basename || '\0' == *basename)
3448 return NULL;
3449
3450 return basename;
3451}
3452
3453
3454struct PlaceLoadClosure
3455{
3456 const char *app_id;
3457 const char *ego_pub_str;
3458};
3459
3460
3461/** Load a place file */
3462int
3463file_place_load (void *cls, const char *place_filename)
3464{
3465 struct PlaceLoadClosure *plcls = cls;
3466
3467 const char *place_pub_str = path_basename (place_filename);
3468 if (NULL == place_pub_str)
3469 {
3470 GNUNET_break (0);
3471 return GNUNET_OK;
3472 }
3473
3474 char *filename = NULL;
3475 GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s",
3476 dir_social, DIR_SEPARATOR,
3477 "places", DIR_SEPARATOR,
3478 plcls->ego_pub_str, DIR_SEPARATOR,
3479 place_pub_str);
3480
3481 uint64_t file_size = 0;
3482 if (GNUNET_OK !=
3483 GNUNET_DISK_file_size (filename, &file_size, GNUNET_YES, GNUNET_YES)
3484 || file_size < sizeof (struct PlaceEnterRequest))
3485 {
3486 GNUNET_free (filename);
3487 return GNUNET_OK;
3488 }
3489
3490 struct PlaceEnterRequest *ereq = GNUNET_malloc (file_size);
3491 ssize_t read_size = GNUNET_DISK_fn_read (filename, ereq, file_size);
3492 GNUNET_free (filename);
3493 if (read_size < 0 || read_size < sizeof (*ereq))
3494 {
3495 GNUNET_free (ereq);
3496 return GNUNET_OK;
3497 }
3498
3499 uint16_t ereq_size = ntohs (ereq->header.size);
3500 if (read_size != ereq_size)
3501 {
3502 GNUNET_free (ereq);
3503 return GNUNET_OK;
3504 }
3505
3506 switch (ntohs (ereq->header.type))
3507 {
3508 case GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER:
3509 if (ereq_size < sizeof (struct HostEnterRequest))
3510 {
3511 GNUNET_free (ereq);
3512 return GNUNET_OK;
3513 }
3514 struct HostEnterRequest *hreq = (struct HostEnterRequest *) ereq;
3515 host_enter (hreq, NULL);
3516 break;
3517
3518 case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER:
3519 if (ereq_size < sizeof (struct GuestEnterRequest))
3520 {
3521 GNUNET_free (ereq);
3522 return GNUNET_OK;
3523 }
3524 struct GuestEnterRequest *greq = (struct GuestEnterRequest *) ereq;
3525 guest_enter (greq, NULL);
3526 break;
3527
3528 default:
3529 GNUNET_free (ereq);
3530 return GNUNET_OK;
3531 }
3532
3533 if (GNUNET_SYSERR == app_place_add (plcls->app_id, ereq))
3534 {
3535 GNUNET_assert (0);
3536 }
3537 GNUNET_free (ereq);
3538 return GNUNET_OK;
3539}
3540
3541
3542/**
3543 * Read @e place_pub_str entries in @a dir_ego
3544 *
3545 * @param dir_ego
3546 * Data directory of an application ego.
3547 * $GNUNET_DATA_HOME/social/apps/$app_id/$ego_pub_str/
3548 */
3549int
3550scan_app_ego_dir (void *cls, const char *dir_ego)
3551{
3552 struct PlaceLoadClosure *plcls = cls;
3553 plcls->ego_pub_str = path_basename (dir_ego);
3554
3555 if (NULL != plcls->ego_pub_str)
3556 GNUNET_DISK_directory_scan (dir_ego, file_place_load, plcls);
3557
3558 return GNUNET_OK;
3559}
3560
3561/**
3562 * Read @e ego_pub_str entries in @a dir_app
3563 *
3564 * @param dir_app
3565 * Data directory of an application.
3566 * $GNUNET_DATA_HOME/social/apps/$app_id/
3567 */
3568int
3569scan_app_dir (void *cls, const char *dir_app)
3570{
3571 if (GNUNET_YES != GNUNET_DISK_directory_test (dir_app, GNUNET_YES))
3572 return GNUNET_OK;
3573
3574 struct PlaceLoadClosure plcls;
3575 plcls.app_id = path_basename (dir_app);
3576
3577 if (NULL != plcls.app_id)
3578 GNUNET_DISK_directory_scan (dir_app, scan_app_ego_dir, &plcls);
3579
3580 return GNUNET_OK;
3581}
3582
3583
3584static void
3585identity_recv_ego (void *cls, struct GNUNET_IDENTITY_Ego *id_ego,
3586 void **ctx, const char *name)
3587{
3588 if (NULL == id_ego) // end of initial list of egos
3589 return;
3590
3591 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3592 "social service received ego %s\n",
3593 name);
3594
3595 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
3596 GNUNET_IDENTITY_ego_get_public_key (id_ego, &ego_pub_key);
3597
3598 struct GNUNET_HashCode ego_pub_hash;
3599 GNUNET_CRYPTO_hash (&ego_pub_key, sizeof (ego_pub_key), &ego_pub_hash);
3600
3601 struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash);
3602 if (NULL == ego && NULL == name)
3603 {
3604 // an ego that is none of our business has been deleted
3605 return;
3606 }
3607 if (NULL != ego)
3608 {
3609 // one of our egos has been changed
3610 GNUNET_free (ego->name);
3611 if (NULL == name)
3612 {
3613 // one of our egos has been deleted
3614 GNUNET_CONTAINER_multihashmap_remove (egos, &ego_pub_hash, ego);
3615 GNUNET_free (ego);
3616 return;
3617 }
3618 }
3619 else
3620 {
3621 ego = GNUNET_malloc (sizeof (*ego));
3622 }
3623 ego->key = *(GNUNET_IDENTITY_ego_get_private_key (id_ego));
3624 size_t name_size = strlen (name) + 1;
3625 ego->name = GNUNET_malloc (name_size);
3626 GNUNET_memcpy (ego->name, name, name_size);
3627
3628 GNUNET_CONTAINER_multihashmap_put (egos, &ego_pub_hash, ego,
3629 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
3630
3631 // FIXME: notify clients about changed ego
3632}
3633
3634
3635/**
3636 * Initialize the PSYC service.
3637 *
3638 * @param cls Closure.
3639 * @param server The initialized server.
3640 * @param c Configuration to use.
3641 */
3642static void
3643run (void *cls,
3644 const struct GNUNET_CONFIGURATION_Handle *c,
3645 struct GNUNET_SERVICE_Handle *svc)
3646{
3647 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3648 "starting social service\n");
3649
3650 cfg = c;
3651 service = svc;
3652 GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer);
3653
3654 hosts = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
3655 guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
3656 place_guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
3657
3658 egos = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
3659 apps = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
3660 places = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO);
3661 apps_places = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO);
3662 //places_apps = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO);
3663
3664 id = GNUNET_IDENTITY_connect (cfg, &identity_recv_ego, NULL);
3665 gns = GNUNET_GNS_connect (cfg);
3666 namestore = GNUNET_NAMESTORE_connect (cfg);
3667 stats = GNUNET_STATISTICS_create ("social", cfg);
3668
3669 if (GNUNET_OK !=
3670 GNUNET_CONFIGURATION_get_value_filename (cfg, "social", "DATA_HOME",
3671 &dir_social))
3672 {
3673 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3674 "social", "DATA_HOME");
3675 GNUNET_break (0);
3676 return;
3677 }
3678 GNUNET_asprintf (&dir_places, "%s%c%s",
3679 dir_social, DIR_SEPARATOR, "places");
3680 GNUNET_asprintf (&dir_apps, "%s%c%s",
3681 dir_social, DIR_SEPARATOR, "apps");
3682
3683 GNUNET_DISK_directory_scan (dir_apps, scan_app_dir, NULL);
3684
3685 GNUNET_SCHEDULER_add_shutdown (shutdown_task, NULL);
3686}
3687
3688
3689/**
3690 * Define "main" method using service macro.
3691 */
3692GNUNET_SERVICE_MAIN
3693("social",
3694 GNUNET_SERVICE_OPTION_NONE,
3695 run,
3696 client_notify_connect,
3697 client_notify_disconnect,
3698 NULL,
3699 GNUNET_MQ_hd_var_size (client_host_enter,
3700 GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER,
3701 struct HostEnterRequest,
3702 NULL),
3703 GNUNET_MQ_hd_var_size (client_guest_enter,
3704 GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER,
3705 struct GuestEnterRequest,
3706 NULL),
3707 GNUNET_MQ_hd_var_size (client_guest_enter_by_name,
3708 GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME,
3709 struct GuestEnterByNameRequest,
3710 NULL),
3711 GNUNET_MQ_hd_var_size (client_join_decision,
3712 GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION,
3713 struct GNUNET_PSYC_JoinDecisionMessage,
3714 NULL),
3715 GNUNET_MQ_hd_var_size (client_psyc_message,
3716 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE,
3717 struct GNUNET_MessageHeader,
3718 NULL),
3719 GNUNET_MQ_hd_var_size (client_history_replay,
3720 GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY,
3721 struct GNUNET_PSYC_HistoryRequestMessage,
3722 NULL),
3723 GNUNET_MQ_hd_var_size (client_state_get,
3724 GNUNET_MESSAGE_TYPE_PSYC_STATE_GET,
3725 struct GNUNET_PSYC_StateRequestMessage,
3726 NULL),
3727 GNUNET_MQ_hd_var_size (client_state_get_prefix,
3728 GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX,
3729 struct GNUNET_PSYC_StateRequestMessage,
3730 NULL),
3731 GNUNET_MQ_hd_var_size (client_zone_add_place,
3732 GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_PLACE,
3733 struct ZoneAddPlaceRequest,
3734 NULL),
3735 GNUNET_MQ_hd_var_size (client_zone_add_nym,
3736 GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_NYM,
3737 struct ZoneAddNymRequest,
3738 NULL),
3739 GNUNET_MQ_hd_var_size (client_app_connect,
3740 GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT,
3741 struct AppConnectRequest,
3742 NULL),
3743 GNUNET_MQ_hd_fixed_size (client_app_detach,
3744 GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH,
3745 struct AppDetachRequest,
3746 NULL),
3747 GNUNET_MQ_hd_fixed_size (client_place_leave,
3748 GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE,
3749 struct GNUNET_MessageHeader,
3750 NULL),
3751 GNUNET_MQ_hd_var_size (client_msg_proc_set,
3752 GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_SET,
3753 struct MsgProcRequest,
3754 NULL),
3755 GNUNET_MQ_hd_fixed_size (client_msg_proc_clear,
3756 GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_CLEAR,
3757 struct GNUNET_MessageHeader,
3758 NULL));
3759
3760/* 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 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19*/
20
21/**
22 * CLI tool to interact with the social service.
23 *
24 * @author Gabor X Toth
25 */
26
27#include <inttypes.h>
28
29#include "platform.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_social_service.h"
32
33#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
34
35#define DATA2ARG(data) data, sizeof (data)
36
37/* operations corresponding to API calls */
38
39/** --status */
40static int op_status;
41
42/** --host-enter */
43static int op_host_enter;
44
45/** --host-reconnect */
46static int op_host_reconnect;
47
48/** --host-leave */
49static int op_host_leave;
50
51/** --host-announce */
52static int op_host_announce;
53
54/** --host-assign */
55static int op_host_assign;
56
57/** --guest-enter */
58static int op_guest_enter;
59
60/** --guest-reconnect */
61static int op_guest_reconnect;
62
63/** --guest-leave */
64static int op_guest_leave;
65
66/** --guest-talk */
67static int op_guest_talk;
68
69/** --replay */
70static int op_replay;
71
72/** --replay-latest */
73static int op_replay_latest;
74
75/** --look-at */
76static int op_look_at;
77
78/** --look-for */
79static int op_look_for;
80
81
82/* options */
83
84/** --app */
85static char *opt_app = "cli";
86
87/** --place */
88static char *opt_place;
89
90/** --ego */
91static char *opt_ego;
92
93/** --gns */
94static char *opt_gns;
95
96/** --peer */
97static char *opt_peer;
98
99/** --follow */
100static int opt_follow;
101
102/** --welcome */
103static int opt_welcome;
104
105/** --deny */
106static int opt_deny;
107
108/** --method */
109static char *opt_method;
110
111/** --data */
112// FIXME: should come from STDIN
113static char *opt_data;
114
115/** --name */
116static char *opt_name;
117
118/** --start */
119static unsigned long long opt_start;
120
121/** --until */
122static unsigned long long opt_until;
123
124/** --limit */
125static unsigned long long opt_limit;
126
127
128/* global vars */
129
130/** exit code */
131static int ret = 1;
132
133/** are we waiting for service to close our connection */
134static char is_disconnecting = 0;
135
136/** Task handle for timeout termination. */
137struct GNUNET_SCHEDULER_Task *timeout_task;
138
139const struct GNUNET_CONFIGURATION_Handle *cfg;
140
141struct GNUNET_PeerIdentity peer, this_peer;
142
143struct GNUNET_SOCIAL_App *app;
144
145/** public key of connected place */
146struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
147
148struct GNUNET_PSYC_Slicer *slicer;
149
150struct GNUNET_SOCIAL_Ego *ego;
151struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
152
153struct GNUNET_SOCIAL_Host *hst;
154struct GNUNET_SOCIAL_Guest *gst;
155struct GNUNET_SOCIAL_Place *plc;
156
157const char *method_received;
158
159
160/* DISCONNECT */
161
162
163/**
164 * Callback called after the host or guest place disconnected.
165 */
166static void
167disconnected (void *cls)
168{
169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnected()\n");
170 GNUNET_SCHEDULER_shutdown ();
171}
172
173
174/**
175 * Callback called after the application disconnected.
176 */
177static void
178app_disconnected (void *cls)
179{
180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "app_disconnected()\n");
181 if (hst || gst)
182 {
183 if (hst)
184 {
185 GNUNET_SOCIAL_host_disconnect (hst, disconnected, NULL);
186 }
187 if (gst)
188 {
189 GNUNET_SOCIAL_guest_disconnect (gst, disconnected, NULL);
190 }
191 }
192 else
193 {
194 GNUNET_SCHEDULER_shutdown ();
195 }
196}
197
198
199/**
200 * Disconnect from connected GNUnet services.
201 */
202static void
203disconnect ()
204{
205 // handle that we get called several times from several places, but should we?
206 if (!is_disconnecting++) {
207 GNUNET_SOCIAL_app_disconnect (app, app_disconnected, NULL);
208 }
209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnect() called for the #%d time\n", is_disconnecting);
210}
211
212
213static void
214scheduler_shutdown (void *cls)
215{
216 disconnect ();
217}
218
219
220/**
221 * Callback called when the program failed to finish the requested operation in time.
222 */
223static void
224timeout (void *cls)
225{
226 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "timeout()\n");
227 disconnect ();
228}
229
230static void
231schedule_success (void *cls)
232{
233 ret = 0;
234 disconnect ();
235}
236
237
238static void
239schedule_fail (void *cls)
240{
241 disconnect ();
242}
243
244
245/**
246 * Schedule exit with success result.
247 */
248static void
249exit_success ()
250{
251 if (timeout_task != NULL)
252 {
253 GNUNET_SCHEDULER_cancel (timeout_task);
254 timeout_task = NULL;
255 }
256 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, schedule_success, NULL);
257}
258
259
260/**
261 * Schedule exit with failure result.
262 */
263static void
264exit_fail ()
265{
266 if (timeout_task != NULL)
267 {
268 GNUNET_SCHEDULER_cancel (timeout_task);
269 timeout_task = NULL;
270 }
271 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, schedule_fail, NULL);
272}
273
274
275/* LEAVE */
276
277
278/**
279 * Callback notifying about the host has left and stopped hosting the place.
280 *
281 * This also indicates the end of the connection to the service.
282 */
283static void
284host_left (void *cls)
285{
286 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
287 "The host has left the place.\n");
288 exit_success ();
289}
290
291
292/**
293 * Leave a place permanently and stop hosting a place.
294 */
295static void
296host_leave ()
297{
298 GNUNET_SOCIAL_host_leave (hst, NULL, host_left, NULL);
299 hst = NULL;
300 plc = NULL;
301}
302
303
304/**
305 * Callback notifying about the guest has left the place.
306 *
307 * This also indicates the end of the connection to the service.
308 */
309static void
310guest_left (void *cls)
311{
312 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
313 "Guest has left the place.\n");
314}
315
316
317/**
318 * Leave a place permanently as guest.
319 */
320static void
321guest_leave ()
322{
323 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
324 // FIXME: wrong use of vars
325 GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
326 "_message", DATA2ARG ("Leaving."));
327 GNUNET_SOCIAL_guest_leave (gst, env, guest_left, NULL);
328 GNUNET_PSYC_env_destroy (env);
329 gst = NULL;
330 plc = NULL;
331}
332
333
334/* ANNOUNCE / ASSIGN / TALK */
335
336
337struct TransmitClosure
338{
339 const char *data;
340 size_t size;
341} tmit;
342
343
344/**
345 * Callback notifying about available buffer space to write message data
346 * when transmitting messages using host_announce() or guest_talk()
347 */
348static int
349notify_data (void *cls, uint16_t *data_size, void *data)
350{
351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
352 "Transmit notify data: %u bytes available\n",
353 *data_size);
354
355 struct TransmitClosure *tmit = cls;
356 uint16_t size = tmit->size < *data_size ? tmit->size : *data_size;
357 *data_size = size;
358 GNUNET_memcpy (data, tmit->data, size);
359
360 tmit->size -= size;
361 tmit->data += size;
362
363 if (0 == tmit->size)
364 {
365 if ((op_host_announce || op_host_assign || op_guest_talk) && !opt_follow)
366 {
367 exit_success ();
368 }
369 return GNUNET_YES;
370 }
371 else
372 {
373 return GNUNET_NO;
374 }
375}
376
377
378/**
379 * Host announcement - send a message to the place.
380 */
381static void
382host_announce (const char *method, const char *data, size_t data_size)
383{
384 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
385 GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
386 "_foo", DATA2ARG ("bar baz"));
387
388 tmit = (struct TransmitClosure) {};
389 tmit.data = data;
390 tmit.size = data_size;
391
392 GNUNET_SOCIAL_host_announce (hst, method, env,
393 notify_data, &tmit,
394 GNUNET_SOCIAL_ANNOUNCE_NONE);
395 GNUNET_PSYC_env_destroy (env);
396}
397
398
399/**
400 * Assign a state var of @a name to the value of @a data.
401 */
402static void
403host_assign (const char *name, const char *data, size_t data_size)
404{
405 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
406 GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN,
407 name, data, data_size);
408
409 tmit = (struct TransmitClosure) {};
410 GNUNET_SOCIAL_host_announce (hst, "_assign", env,
411 notify_data, &tmit,
412 GNUNET_SOCIAL_ANNOUNCE_NONE);
413 GNUNET_PSYC_env_destroy (env);
414}
415
416
417/**
418 * Guest talk request to host.
419 */
420static void
421guest_talk (const char *method,
422 const char *data, size_t data_size)
423{
424 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
425 GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
426 "_foo", DATA2ARG ("bar baz"));
427
428 tmit = (struct TransmitClosure) {};
429 tmit.data = data;
430 tmit.size = data_size;
431
432 GNUNET_SOCIAL_guest_talk (gst, method, env,
433 notify_data, &tmit,
434 GNUNET_SOCIAL_TALK_NONE);
435 GNUNET_PSYC_env_destroy (env);
436}
437
438
439/* HISTORY REPLAY */
440
441
442/**
443 * Callback notifying about the end of history replay results.
444 */
445static void
446recv_history_replay_result (void *cls, int64_t result,
447 const void *data, uint16_t data_size)
448{
449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
450 "Received history replay result: %" PRId64 "\n"
451 "%.*s\n",
452 result, data_size, (const char *) data);
453
454 if (op_replay || op_replay_latest)
455 {
456 exit_success ();
457 }
458}
459
460
461/**
462 * Replay history between a given @a start and @a end message IDs,
463 * optionally filtered by a method @a prefix.
464 */
465static void
466history_replay (uint64_t start, uint64_t end, const char *prefix)
467{
468 GNUNET_SOCIAL_place_history_replay (plc, start, end, prefix,
469 GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
470 slicer,
471 recv_history_replay_result,
472 NULL);
473}
474
475
476/**
477 * Replay latest @a limit messages.
478 */
479static void
480history_replay_latest (uint64_t limit, const char *prefix)
481{
482 GNUNET_SOCIAL_place_history_replay_latest (plc, limit, prefix,
483 GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
484 slicer,
485 recv_history_replay_result,
486 NULL);
487}
488
489
490/* LOOK AT/FOR */
491
492
493/**
494 * Callback notifying about the end of state var results.
495 */
496static void
497look_result (void *cls, int64_t result_code,
498 const void *data, uint16_t data_size)
499{
500 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
501 "Received look result: %" PRId64 "\n", result_code);
502
503 if (op_look_at || op_look_for)
504 {
505 exit_success ();
506 }
507}
508
509
510/**
511 * Callback notifying about a state var result.
512 */
513static void
514look_var (void *cls,
515 const struct GNUNET_MessageHeader *mod,
516 const char *name,
517 const void *value,
518 uint32_t value_size,
519 uint32_t full_value_size)
520{
521 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
522 "Received var: %s\n%.*s\n",
523 name, value_size, (const char *) value);
524}
525
526
527/**
528 * Look for a state var using exact match of the name.
529 */
530static void
531look_at (const char *full_name)
532{
533 GNUNET_SOCIAL_place_look_at (plc, full_name, look_var, look_result, NULL);
534}
535
536
537/**
538 * Look for state vars by name prefix.
539 */
540static void
541look_for (const char *name_prefix)
542{
543 GNUNET_SOCIAL_place_look_for (plc, name_prefix, look_var, look_result, NULL);
544}
545
546
547/* SLICER */
548
549
550/**
551 * Callback notifying about the start of a new incoming message.
552 */
553static void
554slicer_recv_method (void *cls,
555 const struct GNUNET_PSYC_MessageHeader *msg,
556 const struct GNUNET_PSYC_MessageMethod *meth,
557 uint64_t message_id,
558 const char *method_name)
559{
560 method_received = method_name;
561 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
562 "Received method for message ID %" PRIu64 ":\n"
563 "%s (flags: %x)\n",
564 message_id, method_name, ntohl (meth->flags));
565 /* routing header is missing, so we just print double newline */
566 printf("\n");
567 /* we output . instead of | to indicate that this is not proper PSYC syntax */
568 /* FIXME: use libpsyc here */
569}
570
571
572/**
573 * Callback notifying about an incoming modifier.
574 */
575static void
576slicer_recv_modifier (void *cls,
577 const struct GNUNET_PSYC_MessageHeader *msg,
578 const struct GNUNET_MessageHeader *pmsg,
579 uint64_t message_id,
580 enum GNUNET_PSYC_Operator oper,
581 const char *name,
582 const void *value,
583 uint16_t value_size,
584 uint16_t full_value_size)
585{
586#if 0
587 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
588 "Received modifier for message ID %" PRIu64 ":\n"
589 "%c%s: %.*s (size: %u)\n",
590 message_id, oper, name, value_size, (const char *) value, value_size);
591#else
592 /* obviously not binary safe */
593 printf("%c%s\t%.*s\n",
594 oper, name, value_size, (const char *) value);
595#endif
596}
597
598
599/**
600 * Callback notifying about an incoming data fragment.
601 */
602static void
603slicer_recv_data (void *cls,
604 const struct GNUNET_PSYC_MessageHeader *msg,
605 const struct GNUNET_MessageHeader *pmsg,
606 uint64_t message_id,
607 const void *data,
608 uint16_t data_size)
609{
610#if 0
611 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
612 "Received data for message ID %" PRIu64 ":\n"
613 "%.*s\n",
614 message_id, data_size, (const char *) data);
615#else
616 /* obviously not binary safe */
617 printf("%s\n%.*s\n",
618 method_received, data_size, (const char *) data);
619#endif
620}
621
622
623/**
624 * Callback notifying about the end of a message.
625 */
626static void
627slicer_recv_eom (void *cls,
628 const struct GNUNET_PSYC_MessageHeader *msg,
629 const struct GNUNET_MessageHeader *pmsg,
630 uint64_t message_id,
631 uint8_t is_cancelled)
632{
633 printf(".\n");
634 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
635 "Received end of message ID %" PRIu64
636 ", cancelled: %u\n",
637 message_id, is_cancelled);
638}
639
640
641/**
642 * Create a slicer for receiving message parts.
643 */
644static struct GNUNET_PSYC_Slicer *
645slicer_create ()
646{
647 slicer = GNUNET_PSYC_slicer_create ();
648
649 /* register slicer to receive incoming messages with any method name */
650 GNUNET_PSYC_slicer_method_add (slicer, "", NULL,
651 slicer_recv_method, slicer_recv_modifier,
652 slicer_recv_data, slicer_recv_eom, NULL);
653 return slicer;
654}
655
656
657/* GUEST ENTER */
658
659
660/**
661 * Callback called when the guest receives an entry decision from the host.
662 *
663 * It is called once after using guest_enter() or guest_enter_by_name(),
664 * in case of a reconnection only the local enter callback is called.
665 */
666static void
667guest_recv_entry_decision (void *cls,
668 int is_admitted,
669 const struct GNUNET_PSYC_Message *entry_msg)
670{
671 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
672 "Guest received entry decision %d\n",
673 is_admitted);
674
675 if (NULL != entry_msg)
676 {
677 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
678 const char *method_name = NULL;
679 const void *data = NULL;
680 uint16_t data_size = 0;
681 struct GNUNET_PSYC_MessageHeader *
682 pmsg = GNUNET_PSYC_message_header_create_from_psyc (entry_msg);
683 GNUNET_PSYC_message_parse (pmsg, &method_name, env, &data, &data_size);
684 GNUNET_free (pmsg);
685
686 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
687 "%s\n%.*s\n",
688 method_name, data_size, (const char *) data);
689 }
690
691 if (op_guest_enter && !opt_follow)
692 {
693 exit_success ();
694 }
695}
696
697
698/**
699 * Callback called after a guest connection is established to the local service.
700 */
701static void
702guest_recv_local_enter (void *cls, int result,
703 const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key,
704 uint64_t max_message_id)
705{
706 char *pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (pub_key);
707 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
708 "Guest entered local place: %s, max_message_id: %" PRIu64 "\n",
709 pub_str, max_message_id);
710 GNUNET_free (pub_str);
711 GNUNET_assert (0 <= result);
712
713 if (op_guest_enter && !opt_follow)
714 {
715 exit_success ();
716 }
717}
718
719
720/**
721 * Create entry request message.
722 */
723static struct GNUNET_PSYC_Message *
724guest_enter_msg_create ()
725{
726 const char *method_name = "_request_enter";
727 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
728 GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
729 "_foo", DATA2ARG ("bar"));
730 void *data = "let me in";
731 uint16_t data_size = strlen (data) + 1;
732
733 return GNUNET_PSYC_message_create (method_name, env, data, data_size);
734}
735
736
737/**
738 * Enter a place as guest, using its public key and peer ID.
739 */
740static void
741guest_enter (const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key,
742 const struct GNUNET_PeerIdentity *peer)
743{
744 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
745 "Entering to place as guest.\n");
746
747 if (NULL == ego)
748 {
749 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "--ego missing or invalid\n");
750 exit_fail ();
751 return;
752 }
753
754 struct GNUNET_PSYC_Message *join_msg = guest_enter_msg_create ();
755 gst = GNUNET_SOCIAL_guest_enter (app, ego, pub_key,
756 GNUNET_PSYC_SLAVE_JOIN_NONE,
757 peer, 0, NULL, join_msg, slicer_create (),
758 guest_recv_local_enter,
759 guest_recv_entry_decision, NULL);
760 GNUNET_free (join_msg);
761 plc = GNUNET_SOCIAL_guest_get_place (gst);
762}
763
764
765/**
766 * Enter a place as guest using its GNS address.
767 */
768static void
769guest_enter_by_name (const char *gns_name)
770{
771 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
772 "Entering to place by name as guest.\n");
773
774 struct GNUNET_PSYC_Message *join_msg = guest_enter_msg_create ();
775 gst = GNUNET_SOCIAL_guest_enter_by_name (app, ego, gns_name, NULL,
776 join_msg, slicer,
777 guest_recv_local_enter,
778 guest_recv_entry_decision, NULL);
779 GNUNET_free (join_msg);
780 plc = GNUNET_SOCIAL_guest_get_place (gst);
781}
782
783
784/* HOST ENTER */
785
786
787/**
788 * Callback called when a @a nym wants to enter the place.
789 *
790 * The request needs to be replied with an entry decision.
791 */
792static void
793host_answer_door (void *cls,
794 struct GNUNET_SOCIAL_Nym *nym,
795 const char *method_name,
796 struct GNUNET_PSYC_Environment *env,
797 const void *data,
798 size_t data_size)
799{
800 const struct GNUNET_CRYPTO_EcdsaPublicKey *
801 nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym);
802 char *
803 nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key);
804
805 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
806 "Entry request: %s\n", nym_str);
807 GNUNET_free (nym_str);
808
809 if (opt_welcome)
810 {
811 struct GNUNET_PSYC_Message *
812 resp = GNUNET_PSYC_message_create ("_notice_place_admit", env,
813 DATA2ARG ("Welcome, nym!"));
814 GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_YES, resp);
815 GNUNET_free (resp);
816 }
817 else if (opt_deny)
818 {
819 struct GNUNET_PSYC_Message *
820 resp = GNUNET_PSYC_message_create ("_notice_place_refuse", NULL,
821 DATA2ARG ("Go away!"));
822 GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_NO, resp);
823 GNUNET_free (resp);
824 }
825
826
827}
828
829
830/**
831 * Callback called when a @a nym has left the place.
832 */
833static void
834host_farewell (void *cls,
835 const struct GNUNET_SOCIAL_Nym *nym,
836 struct GNUNET_PSYC_Environment *env)
837{
838 const struct GNUNET_CRYPTO_EcdsaPublicKey *
839 nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym);
840 char *
841 nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key);
842
843 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
844 "Farewell: %s\n", nym_str);
845 GNUNET_free (nym_str);
846}
847
848
849/**
850 * Callback called after the host entered the place.
851 */
852static void
853host_entered (void *cls, int result,
854 const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key,
855 uint64_t max_message_id)
856{
857 place_pub_key = *pub_key;
858 char *pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (pub_key);
859 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
860 "Host entered: %s, max_message_id: %" PRIu64 "\n",
861 pub_str, max_message_id);
862 GNUNET_free (pub_str);
863
864 if (op_host_enter && !opt_follow)
865 {
866 exit_success ();
867 }
868}
869
870
871/**
872 * Enter and start hosting a place.
873 */
874static void
875host_enter ()
876{
877 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "host_enter()\n");
878
879 if (NULL == ego)
880 {
881 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "--ego missing or invalid\n");
882 exit_fail ();
883 return;
884 }
885
886 hst = GNUNET_SOCIAL_host_enter (app, ego,
887 GNUNET_PSYC_CHANNEL_PRIVATE,
888 slicer_create (), host_entered,
889 host_answer_door, host_farewell, NULL);
890 plc = GNUNET_SOCIAL_host_get_place (hst);
891}
892
893
894/* PLACE RECONNECT */
895
896
897/**
898 * Perform operations common to both host & guest places.
899 */
900static void
901place_reconnected ()
902{
903 static int first_run = GNUNET_YES;
904 if (GNUNET_NO == first_run)
905 return;
906 first_run = GNUNET_NO;
907
908 if (op_replay) {
909 history_replay (opt_start, opt_until, opt_method);
910 }
911 else if (op_replay_latest) {
912 history_replay_latest (opt_limit, opt_method);
913 }
914 else if (op_look_at) {
915 look_at (opt_name);
916 }
917 else if (op_look_for) {
918 look_for (opt_name);
919 }
920}
921
922
923/**
924 * Callback called after reconnecting to a host place.
925 */
926static void
927host_reconnected (void *cls, int result,
928 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
929 uint64_t max_message_id)
930{
931 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
932 "Host reconnected.\n");
933
934 if (op_host_leave) {
935 host_leave ();
936 }
937 else if (op_host_announce) {
938 host_announce (opt_method, opt_data, strlen (opt_data));
939 }
940 else if (op_host_assign) {
941 host_assign (opt_name, opt_data, strlen (opt_data) + 1);
942 }
943 else {
944 place_reconnected ();
945 }
946}
947
948
949/**
950 * Callback called after reconnecting to a guest place.
951 */
952static void
953guest_reconnected (void *cls, int result,
954 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
955 uint64_t max_message_id)
956{
957 char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (place_pub_key);
958 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
959 "Guest reconnected to place %s.\n", place_pub_str);
960 GNUNET_free (place_pub_str);
961
962 if (op_guest_leave) {
963 guest_leave ();
964 }
965 else if (op_guest_talk) {
966 guest_talk (opt_method, opt_data, strlen (opt_data));
967 }
968 else {
969 place_reconnected ();
970 }
971}
972
973
974/* APP */
975
976
977/**
978 * Callback called after the ego and place callbacks.
979 */
980static void
981app_connected (void *cls)
982{
983 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
984 "App connected: %p\n", cls);
985
986 if (op_status)
987 {
988 exit_success ();
989 }
990 else if (op_host_enter)
991 {
992 host_enter ();
993 }
994 else if (op_guest_enter)
995 {
996 if (opt_gns)
997 {
998 guest_enter_by_name (opt_gns);
999 }
1000 else
1001 {
1002 if (opt_peer)
1003 {
1004 if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (opt_peer,
1005 strlen (opt_peer),
1006 &peer.public_key))
1007 {
1008 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1009 "--peer invalid");
1010 exit_fail ();
1011 return;
1012 }
1013 }
1014 else
1015 {
1016 peer = this_peer;
1017 }
1018 guest_enter (&place_pub_key, &peer);
1019 }
1020 }
1021 printf(".\n");
1022}
1023
1024
1025/**
1026 * Callback notifying about a host place available for reconnection.
1027 */
1028static void
1029app_recv_host (void *cls,
1030 struct GNUNET_SOCIAL_HostConnection *hconn,
1031 struct GNUNET_SOCIAL_Ego *ego,
1032 const struct GNUNET_CRYPTO_EddsaPublicKey *host_pub_key,
1033 enum GNUNET_SOCIAL_AppPlaceState place_state)
1034{
1035 char *host_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (host_pub_key);
1036 printf ("Host\t%s\n", host_pub_str);
1037 GNUNET_free (host_pub_str);
1038
1039 if ((op_host_reconnect || op_host_leave || op_host_announce || op_host_assign
1040 || op_replay || op_replay_latest
1041 || op_look_at || op_look_for)
1042 && 0 == memcmp (&place_pub_key, host_pub_key, sizeof (*host_pub_key)))
1043 {
1044 hst = GNUNET_SOCIAL_host_enter_reconnect (hconn, slicer_create (), host_reconnected,
1045 host_answer_door, host_farewell, NULL);
1046 plc = GNUNET_SOCIAL_host_get_place (hst);
1047 }
1048}
1049
1050
1051/**
1052 * Callback notifying about a guest place available for reconnection.
1053 */
1054static void
1055app_recv_guest (void *cls,
1056 struct GNUNET_SOCIAL_GuestConnection *gconn,
1057 struct GNUNET_SOCIAL_Ego *ego,
1058 const struct GNUNET_CRYPTO_EddsaPublicKey *guest_pub_key,
1059 enum GNUNET_SOCIAL_AppPlaceState place_state)
1060{
1061 char *guest_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (guest_pub_key);
1062 printf ("Guest\t%s\n", guest_pub_str);
1063 GNUNET_free (guest_pub_str);
1064
1065 if ((op_guest_reconnect || op_guest_leave || op_guest_talk
1066 || op_replay || op_replay_latest
1067 || op_look_at || op_look_for)
1068 && 0 == memcmp (&place_pub_key, guest_pub_key, sizeof (*guest_pub_key)))
1069 {
1070 gst = GNUNET_SOCIAL_guest_enter_reconnect (gconn, GNUNET_PSYC_SLAVE_JOIN_NONE,
1071 slicer_create (), guest_reconnected, NULL);
1072 plc = GNUNET_SOCIAL_guest_get_place (gst);
1073 }
1074}
1075
1076
1077/**
1078 * Callback notifying about an available ego.
1079 */
1080static void
1081app_recv_ego (void *cls,
1082 struct GNUNET_SOCIAL_Ego *e,
1083 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub_key,
1084 const char *name)
1085{
1086 char *s = GNUNET_CRYPTO_ecdsa_public_key_to_string (pub_key);
1087 printf ("Ego\t%s\t%s\n", s, name);
1088 GNUNET_free (s);
1089
1090 if (0 == memcmp (&ego_pub_key, pub_key, sizeof (*pub_key))
1091 || (NULL != opt_ego && 0 == strcmp (opt_ego, name)))
1092 {
1093 ego = e;
1094 }
1095
1096}
1097
1098
1099
1100/**
1101 * Establish application connection to receive available egos and places.
1102 */
1103static void
1104app_connect (void *cls)
1105{
1106 app = GNUNET_SOCIAL_app_connect (cfg, opt_app,
1107 app_recv_ego,
1108 app_recv_host,
1109 app_recv_guest,
1110 app_connected,
1111 NULL);
1112}
1113
1114
1115/**
1116 * Main function run by the scheduler.
1117 *
1118 * @param cls closure
1119 * @param args remaining command-line arguments
1120 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1121 * @param c configuration
1122 */
1123static void
1124run (void *cls, char *const *args, const char *cfgfile,
1125 const struct GNUNET_CONFIGURATION_Handle *c)
1126{
1127 cfg = c;
1128 GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer);
1129
1130 if (!opt_method)
1131 opt_method = "message";
1132 if (!opt_data)
1133 opt_data = "";
1134 if (!opt_name)
1135 opt_name = "";
1136
1137 if (! (op_status
1138 || op_host_enter || op_host_reconnect || op_host_leave
1139 || op_host_announce || op_host_assign
1140 || op_guest_enter || op_guest_reconnect
1141 || op_guest_leave || op_guest_talk
1142 || op_replay || op_replay_latest
1143 || op_look_at || op_look_for))
1144 {
1145 op_status = 1;
1146 fputs("Caution: This tool does not produce correct binary safe PSYC syntax.\n\n", stderr);
1147 }
1148
1149 GNUNET_SCHEDULER_add_shutdown (scheduler_shutdown, NULL);
1150 if (!opt_follow)
1151 {
1152 timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, timeout, NULL);
1153 }
1154
1155 if ((op_host_reconnect || op_host_leave || op_host_announce || op_host_assign
1156 || op_guest_reconnect || (op_guest_enter && !opt_gns)
1157 || op_guest_leave || op_guest_talk
1158 || op_replay || op_replay_latest
1159 || op_look_at || op_look_for)
1160 && (!opt_place
1161 || GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (opt_place,
1162 strlen (opt_place),
1163 &place_pub_key)))
1164 {
1165 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1166 _("--place missing or invalid.\n"));
1167 /* FIXME: why does it segfault here? */
1168 exit_fail ();
1169 return;
1170 }
1171
1172 if (opt_ego)
1173 {
1174 if (GNUNET_OK !=
1175 GNUNET_CRYPTO_ecdsa_public_key_from_string (opt_ego,
1176 strlen (opt_ego),
1177 &ego_pub_key))
1178 {
1179 FPRINTF (stderr,
1180 _("Public key `%s' malformed\n"),
1181 opt_ego);
1182 exit_fail ();
1183 return;
1184 }
1185 }
1186
1187 GNUNET_SCHEDULER_add_now (app_connect, NULL);
1188}
1189
1190
1191/**
1192 * The main function to obtain peer information.
1193 *
1194 * @param argc number of arguments from the command line
1195 * @param argv command line arguments
1196 * @return 0 ok, 1 on error
1197 */
1198int
1199main (int argc, char *const *argv)
1200{
1201 int res;
1202 struct GNUNET_GETOPT_CommandLineOption options[] = {
1203 /*
1204 * gnunet program options in addition to the ones below:
1205 *
1206 * -c, --config=FILENAME
1207 * -l, --logfile=LOGFILE
1208 * -L, --log=LOGLEVEL
1209 * -h, --help
1210 * -v, --version
1211 */
1212
1213 /* operations */
1214
1215 GNUNET_GETOPT_option_flag ('A',
1216 "host-assign",
1217 gettext_noop ("assign --name in state to --data"),
1218 &op_host_assign),
1219
1220 GNUNET_GETOPT_option_flag ('B',
1221 "guest-leave",
1222 gettext_noop ("say good-bye and leave somebody else's place"),
1223 &op_guest_leave),
1224
1225 GNUNET_GETOPT_option_flag ('C',
1226 "host-enter",
1227 gettext_noop ("create a place"),
1228 &op_host_enter),
1229
1230 GNUNET_GETOPT_option_flag ('D',
1231 "host-leave",
1232 gettext_noop ("destroy a place we were hosting"),
1233 &op_host_leave),
1234
1235 GNUNET_GETOPT_option_flag ('E',
1236 "guest-enter",
1237 gettext_noop ("enter somebody else's place"),
1238 &op_guest_enter),
1239
1240
1241 GNUNET_GETOPT_option_flag ('F',
1242 "look-for",
1243 gettext_noop ("find state matching name prefix"),
1244 &op_look_for),
1245
1246 GNUNET_GETOPT_option_flag ('H',
1247 "replay-latest",
1248 gettext_noop ("replay history of messages up to the given --limit"),
1249 &op_replay_latest),
1250
1251 GNUNET_GETOPT_option_flag ('N',
1252 "host-reconnect",
1253 gettext_noop ("reconnect to a previously created place"),
1254 &op_host_reconnect),
1255
1256 GNUNET_GETOPT_option_flag ('P',
1257 "host-announce",
1258 gettext_noop ("publish something to a place we are hosting"),
1259 &op_host_announce),
1260
1261 GNUNET_GETOPT_option_flag ('R',
1262 "guest-reconnect",
1263 gettext_noop ("reconnect to a previously entered place"),
1264 &op_guest_reconnect),
1265
1266 GNUNET_GETOPT_option_flag ('S',
1267 "look-at",
1268 gettext_noop ("search for state matching exact name"),
1269 &op_look_at),
1270
1271 GNUNET_GETOPT_option_flag ('T',
1272 "guest-talk",
1273 gettext_noop ("submit something to somebody's place"),
1274 &op_guest_talk),
1275
1276 GNUNET_GETOPT_option_flag ('U',
1277 "status",
1278 gettext_noop ("list of egos and subscribed places"),
1279 &op_status),
1280
1281 GNUNET_GETOPT_option_flag ('X',
1282 "replay",
1283 gettext_noop ("extract and replay history between message IDs --start and --until"),
1284 &op_replay),
1285
1286
1287 /* options */
1288
1289 GNUNET_GETOPT_option_string ('a',
1290 "app",
1291 "APPLICATION_ID",
1292 gettext_noop ("application ID to use when connecting"),
1293 &opt_app),
1294
1295 GNUNET_GETOPT_option_string ('d',
1296 "data",
1297 "DATA",
1298 gettext_noop ("message body or state value"),
1299 &opt_data),
1300
1301 GNUNET_GETOPT_option_string ('e',
1302 "ego",
1303 "NAME|PUBKEY",
1304 gettext_noop ("name or public key of ego"),
1305 &opt_ego),
1306
1307 GNUNET_GETOPT_option_flag ('f',
1308 "follow",
1309 gettext_noop ("wait for incoming messages"),
1310 &opt_follow),
1311
1312 GNUNET_GETOPT_option_string ('g',
1313 "gns",
1314 "GNS_NAME",
1315 gettext_noop ("GNS name"),
1316 &opt_gns),
1317
1318 GNUNET_GETOPT_option_string ('i',
1319 "peer",
1320 "PEER_ID",
1321 gettext_noop ("peer ID for --guest-enter"),
1322 &opt_peer),
1323
1324 GNUNET_GETOPT_option_string ('k',
1325 "name",
1326 "VAR_NAME",
1327 gettext_noop ("name (key) to query from state"),
1328 &opt_name),
1329
1330 GNUNET_GETOPT_option_string ('m',
1331 "method",
1332 "METHOD_NAME",
1333 gettext_noop ("method name"),
1334 &opt_method),
1335
1336 GNUNET_GETOPT_option_ulong ('n',
1337 "limit",
1338 NULL,
1339 gettext_noop ("number of messages to replay from history"),
1340 &opt_limit),
1341
1342 GNUNET_GETOPT_option_string ('p',
1343 "place",
1344 "PUBKEY",
1345 gettext_noop ("key address of place"),
1346 &opt_place),
1347
1348 GNUNET_GETOPT_option_ulong ('s',
1349 "start",
1350 NULL,
1351 gettext_noop ("start message ID for history replay"),
1352 &opt_start),
1353
1354 GNUNET_GETOPT_option_flag ('w',
1355 "welcome",
1356 gettext_noop ("respond to entry requests by admitting all guests"),
1357 &opt_welcome),
1358
1359 GNUNET_GETOPT_option_ulong ('u',
1360 "until",
1361 NULL,
1362 gettext_noop ("end message ID for history replay"),
1363 &opt_until),
1364
1365 GNUNET_GETOPT_option_flag ('y',
1366 "deny",
1367 gettext_noop ("respond to entry requests by refusing all guests"),
1368 &opt_deny),
1369
1370 GNUNET_GETOPT_OPTION_END
1371 };
1372
1373 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1374 return 2;
1375
1376 const char *help =
1377 _ ("gnunet-social - Interact with the social service: enter/leave, send/receive messages, access history and state.\n");
1378 const char *usage =
1379 "gnunet-social [--status]\n"
1380 "\n"
1381 "gnunet-social --host-enter --ego <NAME or PUBKEY> [--follow] [--welcome | --deny]\n"
1382 "gnunet-social --host-reconnect --place <PUBKEY> [--follow] [--welcome | --deny]\n"
1383 "gnunet-social --host-leave --place <PUBKEY>\n"
1384 "gnunet-social --host-assign --place <PUBKEY> --name <NAME> --data <VALUE>\n"
1385// FIXME: some state ops not implemented yet (no hurry)
1386// "gnunet-social --host-augment --place <PUBKEY> --name <NAME> --data <VALUE>\n"
1387// "gnunet-social --host-diminish --place <PUBKEY> --name <NAME> --data <VALUE>\n"
1388// "gnunet-social --host-set --place <PUBKEY> --name <NAME> --data <VALUE>\n"
1389 "gnunet-social --host-announce --place <PUBKEY> --method <METHOD_NAME> --data <MESSAGE_BODY>\n"
1390 "\n"
1391 "gnunet-social --guest-enter --place <PUBKEY> --peer <PEERID> --ego <NAME or PUBKEY> [--follow]\n"
1392 "gnunet-social --guest-enter --gns <GNS_NAME> --ego <NAME or PUBKEY> [--follow]\n"
1393 "gnunet-social --guest-reconnect --place <PUBKEY> [--follow]\n"
1394 "gnunet-social --guest-leave --place <PUBKEY>\n"
1395 "gnunet-social --guest-talk --place <PUBKEY> --method <METHOD_NAME> --data <MESSAGE_BODY>\n"
1396 "\n"
1397 "gnunet-social --replay --place <PUBKEY> --start <MSGID> --until <MSGID> [--method <METHOD_PREFIX>]\n"
1398 "gnunet-social --replay-latest --place <PUBKEY> --limit <MSG_LIMIT> [--method <METHOD_PREFIX>]\n"
1399 "\n"
1400 "gnunet-social --look-at --place <PUBKEY> --name <FULL_NAME>\n"
1401 "gnunet-social --look-for --place <PUBKEY> --name <NAME_PREFIX>\n";
1402
1403 res = GNUNET_PROGRAM_run (argc, argv, help, usage, options, &run, NULL);
1404
1405 GNUNET_free ((void *) argv);
1406
1407 if (GNUNET_OK == res)
1408 return ret;
1409 else
1410 return 1;
1411}
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 @@
1[social]
2START_ON_DEMAND = @START_ON_DEMAND@
3BINARY = gnunet-service-social
4RUN_PER_USER = YES
5
6UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-social.sock
7UNIX_MATCH_UID = YES
8UNIX_MATCH_GID = YES
9
10@UNIXONLY@PORT = 2116
11HOSTNAME = localhost
12ACCEPT_FROM = 127.0.0.1;
13ACCEPT_FROM6 = ::1;
14
15DATA_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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file social/social.h
23 * @brief Common type definitions for the Social service and API.
24 * @author Gabor X Toth
25 */
26
27#ifndef SOCIAL_H
28#define SOCIAL_H
29
30#include "platform.h"
31#include "gnunet_social_service.h"
32
33enum MessageState
34{
35 MSG_STATE_START = 0,
36 MSG_STATE_HEADER = 1,
37 MSG_STATE_METHOD = 2,
38 MSG_STATE_MODIFIER = 3,
39 MSG_STATE_MOD_CONT = 4,
40 MSG_STATE_DATA = 5,
41 MSG_STATE_END = 6,
42 MSG_STATE_CANCEL = 7,
43 MSG_STATE_ERROR = 8,
44};
45
46
47GNUNET_NETWORK_STRUCT_BEGIN
48
49/**** library -> service ****/
50
51
52struct AppConnectRequest
53{
54 /**
55 * Type: GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT
56 */
57 struct GNUNET_MessageHeader header;
58
59 /* Followed by char *app_id */
60};
61
62
63struct AppDetachRequest
64{
65 /**
66 * Type: GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH
67 */
68 struct GNUNET_MessageHeader header;
69
70 /**
71 * Public key of place.
72 */
73 struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
74
75 /**
76 * Public key of ego.
77 */
78 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
79
80 /**
81 * Operation ID.
82 */
83 uint64_t op_id GNUNET_PACKED;
84};
85
86
87struct MsgProcRequest
88{
89 /**
90 * Type: GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_SET
91 */
92 struct GNUNET_MessageHeader header;
93
94 /**
95 * @see enum GNUNET_SOCIAL_MsgProcFlags
96 */
97 uint32_t flags;
98
99 /* Followed by char *method_prefix */
100};
101
102
103struct HostEnterRequest
104{
105 /**
106 * Type: GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER
107 */
108 struct GNUNET_MessageHeader header;
109
110 uint32_t policy GNUNET_PACKED;
111
112 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
113
114 struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
115
116 struct GNUNET_CRYPTO_EddsaPrivateKey place_key;
117
118 /* Followed by char *app_id */
119};
120
121
122struct GuestEnterRequest
123{
124 /**
125 * Type: GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER
126 */
127 struct GNUNET_MessageHeader header;
128
129 uint32_t relay_count GNUNET_PACKED;
130
131 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
132
133 struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
134
135 struct GNUNET_PeerIdentity origin;
136
137 uint32_t flags GNUNET_PACKED;
138
139 /* Followed by char *app_id */
140 /* Followed by struct GNUNET_PeerIdentity relays[relay_count] */
141 /* Followed by struct GNUNET_MessageHeader *join_msg */
142};
143
144
145/** Compatible parts of HostEnterRequest and GuestEnterRequest */
146struct PlaceEnterRequest
147{
148 struct GNUNET_MessageHeader header;
149
150 uint32_t reserved GNUNET_PACKED;
151
152 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
153
154 struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
155};
156
157
158struct EgoPlacePublicKey
159{
160 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
161 struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
162};
163
164
165struct GuestEnterByNameRequest
166{
167 /**
168 * Type: GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME
169 */
170 struct GNUNET_MessageHeader header;
171
172 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
173
174 /* Followed by char *app_id */
175 /* Followed by char *gns_name */
176 /* Followed by char *password */
177 /* Followed by struct GNUNET_MessageHeader *join_msg */
178};
179
180
181struct ZoneAddPlaceRequest
182{
183 struct GNUNET_MessageHeader header;
184
185 uint32_t relay_count GNUNET_PACKED;
186
187 /**
188 * Operation ID.
189 */
190 uint64_t op_id;
191
192 /**
193 * Expiration time: absolute value in us.
194 */
195 uint64_t expiration_time;
196
197 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
198
199 struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
200
201 struct GNUNET_PeerIdentity origin;
202
203 /* Followed by const char *name */
204 /* Followed by const char *password */
205 /* Followed by struct GNUNET_PeerIdentity *relays[relay_count] */
206};
207
208
209struct ZoneAddNymRequest
210{
211 struct GNUNET_MessageHeader header;
212
213 /**
214 * Operation ID.
215 */
216 uint64_t op_id;
217
218 /**
219 * Expiration time: absolute value in us.
220 */
221 uint64_t expiration_time;
222
223 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
224
225 struct GNUNET_CRYPTO_EcdsaPublicKey nym_pub_key;
226
227 /* Followed by const char *name */
228};
229
230
231/**** service -> library ****/
232
233
234struct AppEgoMessage
235{
236 /**
237 * Type: GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO
238 */
239 struct GNUNET_MessageHeader header;
240
241 /**
242 * Public key of ego.
243 */
244 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
245
246 /* Followed by char *name */
247};
248
249
250struct AppPlaceMessage
251{
252 /**
253 * Type: GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE
254 */
255 struct GNUNET_MessageHeader header;
256
257 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
258
259 struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
260
261 uint8_t is_host;
262
263 uint8_t place_state;
264};
265
266
267struct HostEnterAck {
268 /**
269 * Type: GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK
270 */
271 struct GNUNET_MessageHeader header;
272
273 /**
274 * Status code for the operation.
275 */
276 uint32_t result_code GNUNET_PACKED;
277
278 /**
279 * Last message ID sent to the channel.
280 */
281 uint64_t max_message_id GNUNET_PACKED;
282
283 /**
284 * Public key of the place.
285 */
286 struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
287};
288
289
290GNUNET_NETWORK_STRUCT_END
291
292#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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @author Gabor X Toth
23 *
24 * @file
25 * Social service; implements social interactions using the PSYC service.
26 */
27
28#include <inttypes.h>
29#include <string.h>
30
31#include "platform.h"
32#include "gnunet_util_lib.h"
33#include "gnunet_psyc_service.h"
34#include "gnunet_psyc_util_lib.h"
35#include "gnunet_social_service.h"
36#include "social.h"
37
38#define LOG(kind,...) GNUNET_log_from (kind, "social-api",__VA_ARGS__)
39
40/**
41 * Handle for an ego.
42 */
43struct GNUNET_SOCIAL_Ego
44{
45 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
46 struct GNUNET_HashCode pub_key_hash;
47 char *name;
48};
49
50
51/**
52 * Handle for a pseudonym of another user in the network.
53 */
54struct GNUNET_SOCIAL_Nym
55{
56 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
57 struct GNUNET_HashCode pub_key_hash;
58};
59
60
61/**
62 * Handle for an application.
63 */
64struct GNUNET_SOCIAL_App
65{
66 /**
67 * Configuration to use.
68 */
69 const struct GNUNET_CONFIGURATION_Handle *cfg;
70
71 /**
72 * Client connection to the service.
73 */
74 struct GNUNET_MQ_Handle *mq;
75
76 /**
77 * Message to send on connect.
78 */
79 struct GNUNET_MQ_Envelope *connect_env;
80
81 /**
82 * Time to wait until we try to reconnect on failure.
83 */
84 struct GNUNET_TIME_Relative reconnect_delay;
85
86 /**
87 * Task for reconnecting when the listener fails.
88 */
89 struct GNUNET_SCHEDULER_Task *reconnect_task;
90
91 /**
92 * Async operations.
93 */
94 struct GNUNET_OP_Handle *op;
95
96 /**
97 * Function called after disconnected from the service.
98 */
99 GNUNET_ContinuationCallback disconnect_cb;
100
101 /**
102 * Closure for @a disconnect_cb.
103 */
104 void *disconnect_cls;
105
106 /**
107 * Application ID.
108 */
109 char *id;
110
111 /**
112 * Hash map of all egos.
113 * pub_key_hash -> struct GNUNET_SOCIAL_Ego *
114 */
115 struct GNUNET_CONTAINER_MultiHashMap *egos;
116
117 GNUNET_SOCIAL_AppEgoCallback ego_cb;
118 GNUNET_SOCIAL_AppHostPlaceCallback host_cb;
119 GNUNET_SOCIAL_AppGuestPlaceCallback guest_cb;
120 GNUNET_SOCIAL_AppConnectedCallback connected_cb;
121 void *cb_cls;
122};
123
124
125struct GNUNET_SOCIAL_HostConnection
126{
127 struct GNUNET_SOCIAL_App *app;
128
129 struct AppPlaceMessage plc_msg;
130};
131
132
133struct GNUNET_SOCIAL_GuestConnection
134{
135 struct GNUNET_SOCIAL_App *app;
136
137 struct AppPlaceMessage plc_msg;
138};
139
140
141/**
142 * Handle for a place where social interactions happen.
143 */
144struct GNUNET_SOCIAL_Place
145{
146 /**
147 * Configuration to use.
148 */
149 const struct GNUNET_CONFIGURATION_Handle *cfg;
150
151 /**
152 * Client connection to the service.
153 */
154 struct GNUNET_MQ_Handle *mq;
155
156 /**
157 * Message to send on connect.
158 */
159 struct GNUNET_MQ_Envelope *connect_env;
160
161 /**
162 * Time to wait until we try to reconnect on failure.
163 */
164 struct GNUNET_TIME_Relative reconnect_delay;
165
166 /**
167 * Task for reconnecting when the listener fails.
168 */
169 struct GNUNET_SCHEDULER_Task *reconnect_task;
170
171 /**
172 * Async operations.
173 */
174 struct GNUNET_OP_Handle *op;
175
176 /**
177 * Transmission handle.
178 */
179 struct GNUNET_PSYC_TransmitHandle *tmit;
180
181 /**
182 * Slicer for processing incoming messages.
183 */
184 struct GNUNET_PSYC_Slicer *slicer;
185
186 // FIXME: do we need is_disconnecing like on the psyc and multicast APIs?
187 /**
188 * Function called after disconnected from the service.
189 */
190 GNUNET_ContinuationCallback disconnect_cb;
191
192 /**
193 * Closure for @a disconnect_cb.
194 */
195 void *disconnect_cls;
196
197 /**
198 * Public key of the place.
199 */
200 struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
201
202 /**
203 * Public key of the ego.
204 */
205 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
206
207 /**
208 * Does this place belong to a host (#GNUNET_YES) or guest (#GNUNET_NO)?
209 */
210 uint8_t is_host;
211};
212
213
214/**
215 * Host handle for a place that we entered.
216 */
217struct GNUNET_SOCIAL_Host
218{
219 struct GNUNET_SOCIAL_Place plc;
220
221 /**
222 * Slicer for processing incoming messages from guests.
223 */
224 struct GNUNET_PSYC_Slicer *slicer;
225
226 GNUNET_SOCIAL_HostEnterCallback enter_cb;
227
228 GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb;
229
230 GNUNET_SOCIAL_FarewellCallback farewell_cb;
231
232 /**
233 * Closure for callbacks.
234 */
235 void *cb_cls;
236
237 struct GNUNET_SOCIAL_Nym *notice_place_leave_nym;
238 struct GNUNET_PSYC_Environment *notice_place_leave_env;
239};
240
241
242/**
243 * Guest handle for place that we entered.
244 */
245struct GNUNET_SOCIAL_Guest
246{
247 struct GNUNET_SOCIAL_Place plc;
248
249 GNUNET_SOCIAL_GuestEnterCallback enter_cb;
250
251 GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb;
252
253 /**
254 * Closure for callbacks.
255 */
256 void *cb_cls;
257};
258
259
260/**
261 * Hash map of all nyms.
262 * pub_key_hash -> struct GNUNET_SOCIAL_Nym *
263 */
264struct GNUNET_CONTAINER_MultiHashMap *nyms;
265
266
267/**
268 * Handle for an announcement request.
269 */
270struct GNUNET_SOCIAL_Announcement
271{
272
273};
274
275
276/**
277 * A talk request.
278 */
279struct GNUNET_SOCIAL_TalkRequest
280{
281
282};
283
284
285/**
286 * A history lesson.
287 */
288struct GNUNET_SOCIAL_HistoryRequest
289{
290 /**
291 * Place.
292 */
293 struct GNUNET_SOCIAL_Place *plc;
294
295 /**
296 * Operation ID.
297 */
298 uint64_t op_id;
299
300 /**
301 * Slicer for processing incoming messages.
302 */
303 struct GNUNET_PSYC_Slicer *slicer;
304
305 /**
306 * Function to call when the operation finished.
307 */
308 GNUNET_ResultCallback result_cb;
309
310 /**
311 * Closure for @a result_cb.
312 */
313 void *cls;
314};
315
316
317struct GNUNET_SOCIAL_LookHandle
318{
319 /**
320 * Place.
321 */
322 struct GNUNET_SOCIAL_Place *plc;
323
324 /**
325 * Operation ID.
326 */
327 uint64_t op_id;
328
329 /**
330 * State variable result callback.
331 */
332 GNUNET_PSYC_StateVarCallback var_cb;
333
334 /**
335 * Function to call when the operation finished.
336 */
337 GNUNET_ResultCallback result_cb;
338
339 /**
340 * Name of current modifier being received.
341 */
342 char *mod_name;
343
344 /**
345 * Size of current modifier value being received.
346 */
347 size_t mod_value_size;
348
349 /**
350 * Remaining size of current modifier value still to be received.
351 */
352 size_t mod_value_remaining;
353
354 /**
355 * Closure for @a result_cb.
356 */
357 void *cls;
358};
359
360
361struct ZoneAddPlaceHandle
362{
363 GNUNET_ResultCallback result_cb;
364 void *result_cls;
365};
366
367
368struct ZoneAddNymHandle
369{
370 GNUNET_ResultCallback result_cb;
371 void *result_cls;
372};
373
374
375/*** CLEANUP / DISCONNECT ***/
376
377
378static void
379host_cleanup (struct GNUNET_SOCIAL_Host *hst)
380{
381 if (NULL != hst->slicer)
382 {
383 GNUNET_PSYC_slicer_destroy (hst->slicer);
384 hst->slicer = NULL;
385 }
386 GNUNET_free (hst);
387}
388
389
390static void
391guest_cleanup (struct GNUNET_SOCIAL_Guest *gst)
392{
393 GNUNET_free (gst);
394}
395
396
397static void
398place_cleanup (struct GNUNET_SOCIAL_Place *plc)
399{
400 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
401 "cleaning up place %p\n",
402 plc);
403 if (NULL != plc->tmit)
404 {
405 GNUNET_PSYC_transmit_destroy (plc->tmit);
406 plc->tmit = NULL;
407 }
408 if (NULL != plc->connect_env)
409 {
410 GNUNET_MQ_discard (plc->connect_env);
411 plc->connect_env = NULL;
412 }
413 if (NULL != plc->mq)
414 {
415 GNUNET_MQ_destroy (plc->mq);
416 plc->mq = NULL;
417 }
418 if (NULL != plc->disconnect_cb)
419 {
420 plc->disconnect_cb (plc->disconnect_cls);
421 plc->disconnect_cb = NULL;
422 }
423
424 (GNUNET_YES == plc->is_host)
425 ? host_cleanup ((struct GNUNET_SOCIAL_Host *) plc)
426 : guest_cleanup ((struct GNUNET_SOCIAL_Guest *) plc);
427}
428
429
430static void
431place_disconnect (struct GNUNET_SOCIAL_Place *plc)
432{
433 place_cleanup (plc);
434}
435
436
437/*** NYM ***/
438
439static struct GNUNET_SOCIAL_Nym *
440nym_get_or_create (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub_key)
441{
442 struct GNUNET_SOCIAL_Nym *nym = NULL;
443 struct GNUNET_HashCode pub_key_hash;
444
445 if (NULL == pub_key)
446 return NULL;
447
448 GNUNET_CRYPTO_hash (pub_key, sizeof (*pub_key), &pub_key_hash);
449
450 if (NULL == nyms)
451 nyms = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
452 else
453 nym = GNUNET_CONTAINER_multihashmap_get (nyms, &pub_key_hash);
454
455 if (NULL == nym)
456 {
457 nym = GNUNET_new (struct GNUNET_SOCIAL_Nym);
458 nym->pub_key = *pub_key;
459 nym->pub_key_hash = pub_key_hash;
460 GNUNET_CONTAINER_multihashmap_put (nyms, &nym->pub_key_hash, nym,
461 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
462 }
463 return nym;
464}
465
466
467static void
468nym_destroy (struct GNUNET_SOCIAL_Nym *nym)
469{
470 GNUNET_CONTAINER_multihashmap_remove (nyms, &nym->pub_key_hash, nym);
471 GNUNET_free (nym);
472}
473
474
475/*** MESSAGE HANDLERS ***/
476
477/** _notice_place_leave from guests */
478
479static void
480host_recv_notice_place_leave_method (void *cls,
481 const struct GNUNET_PSYC_MessageHeader *msg,
482 const struct GNUNET_PSYC_MessageMethod *meth,
483 uint64_t message_id,
484 const char *method_name)
485{
486 struct GNUNET_SOCIAL_Host *hst = cls;
487
488 if (0 == memcmp (&(struct GNUNET_CRYPTO_EcdsaPublicKey) {},
489 &msg->slave_pub_key, sizeof (msg->slave_pub_key)))
490 return;
491
492 struct GNUNET_SOCIAL_Nym *nym = nym_get_or_create (&msg->slave_pub_key);
493
494 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
495 "Host received method for message ID %" PRIu64 " from nym %s: %s\n",
496 message_id, GNUNET_h2s (&nym->pub_key_hash), method_name);
497
498 hst->notice_place_leave_nym = (struct GNUNET_SOCIAL_Nym *) nym;
499 hst->notice_place_leave_env = GNUNET_PSYC_env_create ();
500
501 char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&hst->notice_place_leave_nym->pub_key);
502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
503 "_notice_place_leave: got method from nym %s (%s).\n",
504 GNUNET_h2s (&hst->notice_place_leave_nym->pub_key_hash), str);
505 GNUNET_free (str);
506}
507
508
509static void
510host_recv_notice_place_leave_modifier (void *cls,
511 const struct GNUNET_PSYC_MessageHeader *msg,
512 const struct GNUNET_MessageHeader *pmsg,
513 uint64_t message_id,
514 enum GNUNET_PSYC_Operator oper,
515 const char *name,
516 const void *value,
517 uint16_t value_size,
518 uint16_t full_value_size)
519{
520 struct GNUNET_SOCIAL_Host *hst = cls;
521 if (NULL == hst->notice_place_leave_env)
522 return;
523
524 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
525 "Host received modifier for _notice_place_leave message with ID %" PRIu64 ":\n"
526 "%c%s: %.*s\n",
527 message_id, oper, name, value_size, (const char *) value);
528
529 /* skip _nym, it's added later in eom() */
530 if (0 == memcmp (name, "_nym", sizeof ("_nym"))
531 || 0 == memcmp (name, "_nym_", sizeof ("_nym_") - 1))
532 return;
533
534 GNUNET_PSYC_env_add (hst->notice_place_leave_env,
535 GNUNET_PSYC_OP_SET, name, value, value_size);
536}
537
538
539static void
540host_recv_notice_place_leave_eom (void *cls,
541 const struct GNUNET_PSYC_MessageHeader *msg,
542 const struct GNUNET_MessageHeader *pmsg,
543 uint64_t message_id,
544 uint8_t is_cancelled)
545{
546 struct GNUNET_SOCIAL_Host *hst = cls;
547 if (NULL == hst->notice_place_leave_env)
548 return;
549
550 char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&hst->notice_place_leave_nym->pub_key);
551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
552 "_notice_place_leave: got EOM from nym %s (%s).\n",
553 GNUNET_h2s (&hst->notice_place_leave_nym->pub_key_hash), str);
554 GNUNET_free (str);
555
556 if (GNUNET_YES != is_cancelled)
557 {
558 if (NULL != hst->farewell_cb)
559 hst->farewell_cb (hst->cb_cls, hst->notice_place_leave_nym,
560 hst->notice_place_leave_env);
561 /* announce leaving guest to place */
562 GNUNET_PSYC_env_add (hst->notice_place_leave_env, GNUNET_PSYC_OP_SET,
563 "_nym", hst->notice_place_leave_nym,
564 sizeof (*hst->notice_place_leave_nym));
565 GNUNET_SOCIAL_host_announce (hst, "_notice_place_leave",
566 hst->notice_place_leave_env,
567 NULL, NULL, GNUNET_SOCIAL_ANNOUNCE_NONE);
568 nym_destroy (hst->notice_place_leave_nym);
569 }
570 GNUNET_PSYC_env_destroy (hst->notice_place_leave_env);
571 hst->notice_place_leave_env = NULL;
572}
573
574
575/*** PLACE ***/
576
577
578static int
579check_place_result (void *cls,
580 const struct GNUNET_OperationResultMessage *res)
581{
582 uint16_t size = ntohs (res->header.size);
583 if (size < sizeof (*res))
584 { /* Error, message too small. */
585 GNUNET_break (0);
586 return GNUNET_SYSERR;
587 }
588 return GNUNET_OK;
589}
590
591
592static void
593handle_place_result (void *cls,
594 const struct GNUNET_OperationResultMessage *res)
595{
596 struct GNUNET_SOCIAL_Place *plc = cls;
597
598 uint16_t size = ntohs (res->header.size);
599 uint16_t data_size = size - sizeof (*res);
600 const char *data = (0 < data_size) ? (const char *) &res[1] : NULL;
601
602 GNUNET_OP_result (plc->op, GNUNET_ntohll (res->op_id),
603 GNUNET_ntohll (res->result_code),
604 data, data_size, NULL);
605}
606
607
608static int
609check_app_result (void *cls,
610 const struct GNUNET_OperationResultMessage *res)
611{
612 uint16_t size = ntohs (res->header.size);
613 if (size < sizeof (*res))
614 { /* Error, message too small. */
615 GNUNET_break (0);
616 return GNUNET_SYSERR;
617 }
618 return GNUNET_OK;
619}
620
621
622static void
623handle_app_result (void *cls,
624 const struct GNUNET_OperationResultMessage *res)
625{
626 struct GNUNET_SOCIAL_App *app = cls;
627
628 uint16_t size = ntohs (res->header.size);
629 uint16_t data_size = size - sizeof (*res);
630 const char *data = (0 < data_size) ? (const char *) &res[1] : NULL;
631
632 GNUNET_OP_result (app->op, GNUNET_ntohll (res->op_id),
633 GNUNET_ntohll (res->result_code),
634 data, data_size, NULL);
635}
636
637
638static void
639op_recv_history_result (void *cls, int64_t result,
640 const void *err_msg, uint16_t err_msg_size)
641{
642 LOG (GNUNET_ERROR_TYPE_DEBUG,
643 "Received history replay result: %" PRId64 ".\n", result);
644
645 struct GNUNET_SOCIAL_HistoryRequest *hist = cls;
646
647 if (NULL != hist->result_cb)
648 hist->result_cb (hist->cls, result, err_msg, err_msg_size);
649
650 GNUNET_free (hist);
651}
652
653
654static void
655op_recv_state_result (void *cls, int64_t result,
656 const void *err_msg, uint16_t err_msg_size)
657{
658 LOG (GNUNET_ERROR_TYPE_DEBUG,
659 "Received state request result: %" PRId64 ".\n", result);
660
661 struct GNUNET_SOCIAL_LookHandle *look = cls;
662
663 if (NULL != look->result_cb)
664 look->result_cb (look->cls, result, err_msg, err_msg_size);
665
666 GNUNET_free (look);
667}
668
669
670static int
671check_place_history_result (void *cls,
672 const struct GNUNET_OperationResultMessage *res)
673{
674 struct GNUNET_PSYC_MessageHeader *
675 pmsg = (struct GNUNET_PSYC_MessageHeader *) GNUNET_MQ_extract_nested_mh (res);
676 uint16_t size = ntohs (res->header.size);
677
678 if (NULL == pmsg || size < sizeof (*res) + sizeof (*pmsg))
679 { /* Error, message too small. */
680 GNUNET_break (0);
681 return GNUNET_SYSERR;
682 }
683 return GNUNET_OK;
684}
685
686
687static void
688handle_place_history_result (void *cls,
689 const struct GNUNET_OperationResultMessage *res)
690{
691 struct GNUNET_SOCIAL_Place *plc = cls;
692 struct GNUNET_PSYC_MessageHeader *
693 pmsg = (struct GNUNET_PSYC_MessageHeader *) GNUNET_MQ_extract_nested_mh (res);
694
695 LOG (GNUNET_ERROR_TYPE_DEBUG,
696 "%p Received historic fragment for message #%" PRIu64 ".\n",
697 plc, GNUNET_ntohll (pmsg->message_id));
698
699 GNUNET_ResultCallback result_cb = NULL;
700 struct GNUNET_SOCIAL_HistoryRequest *hist = NULL;
701
702 if (GNUNET_YES != GNUNET_OP_get (plc->op,
703 GNUNET_ntohll (res->op_id),
704 &result_cb, (void *) &hist, NULL))
705 { /* Operation not found. */
706 LOG (GNUNET_ERROR_TYPE_WARNING,
707 "%p Replay operation not found for historic fragment of message #%"
708 PRIu64 ".\n",
709 plc, GNUNET_ntohll (pmsg->message_id));
710 return;
711 }
712
713 GNUNET_PSYC_slicer_message (hist->slicer,
714 (const struct GNUNET_PSYC_MessageHeader *) pmsg);
715}
716
717
718static int
719check_place_state_result (void *cls,
720 const struct GNUNET_OperationResultMessage *res)
721{
722 const struct GNUNET_MessageHeader *mod = GNUNET_MQ_extract_nested_mh (res);
723 if (NULL == mod)
724 {
725 GNUNET_break_op (0);
726 LOG (GNUNET_ERROR_TYPE_WARNING,
727 "Invalid modifier in state result\n");
728 return GNUNET_SYSERR;
729 }
730
731 uint16_t size = ntohs (res->header.size);
732 uint16_t mod_size = ntohs (mod->size);
733 if (size - sizeof (*res) != mod_size)
734 {
735 GNUNET_break_op (0);
736 LOG (GNUNET_ERROR_TYPE_WARNING,
737 "Invalid modifier size in state result: %u - %u != %u\n",
738 ntohs (res->header.size), sizeof (*res), mod_size);
739 return GNUNET_SYSERR;
740 }
741 return GNUNET_OK;
742}
743
744
745static void
746handle_place_state_result (void *cls,
747 const struct GNUNET_OperationResultMessage *res)
748{
749 struct GNUNET_SOCIAL_Place *plc = cls;
750
751 GNUNET_ResultCallback result_cb = NULL;
752 struct GNUNET_SOCIAL_LookHandle *look = NULL;
753
754 if (GNUNET_YES != GNUNET_OP_get (plc->op,
755 GNUNET_ntohll (res->op_id),
756 &result_cb, (void *) &look, NULL))
757 { /* Operation not found. */
758 return;
759 }
760
761 const struct GNUNET_MessageHeader *mod = GNUNET_MQ_extract_nested_mh (res);
762 uint16_t mod_size = ntohs (mod->size);
763
764 switch (ntohs (mod->type))
765 {
766 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
767 {
768 const struct GNUNET_PSYC_MessageModifier *
769 pmod = (const struct GNUNET_PSYC_MessageModifier *) mod;
770
771 const char *name = (const char *) &pmod[1];
772 uint16_t name_size = ntohs (pmod->name_size);
773 if (0 == name_size
774 || mod_size - sizeof (*pmod) < name_size
775 || '\0' != name[name_size - 1])
776 {
777 GNUNET_break_op (0);
778 LOG (GNUNET_ERROR_TYPE_WARNING,
779 "Invalid modifier name in state result\n");
780 return;
781 }
782 look->mod_value_size = ntohs (pmod->value_size);
783 look->var_cb (look->cls, mod, name, name + name_size,
784 mod_size - sizeof (*mod) - name_size,
785 look->mod_value_size);
786 if (look->mod_value_size > mod_size - sizeof (*mod) - name_size)
787 {
788 look->mod_value_remaining = look->mod_value_size;
789 look->mod_name = GNUNET_malloc (name_size);
790 GNUNET_memcpy (look->mod_name, name, name_size);
791 }
792 break;
793 }
794
795 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
796 look->var_cb (look->cls, mod, look->mod_name, (const char *) &mod[1],
797 mod_size - sizeof (*mod), look->mod_value_size);
798 look->mod_value_remaining -= mod_size - sizeof (*mod);
799 if (0 == look->mod_value_remaining)
800 {
801 GNUNET_free (look->mod_name);
802 }
803 break;
804 }
805}
806
807
808static void
809handle_place_message_ack (void *cls,
810 const struct GNUNET_MessageHeader *msg)
811{
812 struct GNUNET_SOCIAL_Place *plc = cls;
813
814 GNUNET_PSYC_transmit_got_ack (plc->tmit);
815}
816
817
818static int
819check_place_message (void *cls,
820 const struct GNUNET_PSYC_MessageHeader *pmsg)
821{
822 return GNUNET_OK;
823}
824
825
826static void
827handle_place_message (void *cls,
828 const struct GNUNET_PSYC_MessageHeader *pmsg)
829{
830 struct GNUNET_SOCIAL_Place *plc = cls;
831
832 GNUNET_PSYC_slicer_message (plc->slicer, pmsg);
833}
834
835
836static int
837check_host_message (void *cls,
838 const struct GNUNET_PSYC_MessageHeader *pmsg)
839{
840 return GNUNET_OK;
841}
842
843
844static void
845handle_host_message (void *cls,
846 const struct GNUNET_PSYC_MessageHeader *pmsg)
847{
848 struct GNUNET_SOCIAL_Host *hst = cls;
849
850 GNUNET_PSYC_slicer_message (hst->slicer, pmsg);
851 GNUNET_PSYC_slicer_message (hst->plc.slicer, pmsg);
852}
853
854
855static void
856handle_host_enter_ack (void *cls,
857 const struct HostEnterAck *hack)
858{
859 struct GNUNET_SOCIAL_Host *hst = cls;
860
861 hst->plc.pub_key = hack->place_pub_key;
862
863 int32_t result = ntohl (hack->result_code);
864 if (NULL != hst->enter_cb)
865 hst->enter_cb (hst->cb_cls, result, &hack->place_pub_key,
866 GNUNET_ntohll (hack->max_message_id));
867}
868
869
870static int
871check_host_enter_request (void *cls,
872 const struct GNUNET_PSYC_JoinRequestMessage *req)
873{
874 return GNUNET_OK;
875}
876
877
878static void
879handle_host_enter_request (void *cls,
880 const struct GNUNET_PSYC_JoinRequestMessage *req)
881{
882 struct GNUNET_SOCIAL_Host *hst = cls;
883
884 if (NULL == hst->answer_door_cb)
885 return;
886
887 const char *method_name = NULL;
888 struct GNUNET_PSYC_Environment *env = NULL;
889 struct GNUNET_PSYC_MessageHeader *entry_pmsg = NULL;
890 const void *data = NULL;
891 uint16_t data_size = 0;
892 char *str;
893 const struct GNUNET_PSYC_Message *join_msg = NULL;
894
895 do
896 {
897 if (sizeof (*req) + sizeof (*join_msg) <= ntohs (req->header.size))
898 {
899 join_msg = (struct GNUNET_PSYC_Message *) GNUNET_MQ_extract_nested_mh (req);
900 LOG (GNUNET_ERROR_TYPE_DEBUG,
901 "Received join_msg of type %u and size %u.\n",
902 ntohs (join_msg->header.type), ntohs (join_msg->header.size));
903
904 env = GNUNET_PSYC_env_create ();
905 entry_pmsg = GNUNET_PSYC_message_header_create_from_psyc (join_msg);
906 if (GNUNET_OK != GNUNET_PSYC_message_parse (entry_pmsg, &method_name, env,
907 &data, &data_size))
908 {
909 GNUNET_break_op (0);
910 str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&req->slave_pub_key);
911 LOG (GNUNET_ERROR_TYPE_WARNING,
912 "Ignoring invalid entry request from nym %s.\n",
913 str);
914 GNUNET_free (str);
915 break;
916 }
917 }
918
919 struct GNUNET_SOCIAL_Nym *nym = nym_get_or_create (&req->slave_pub_key);
920 hst->answer_door_cb (hst->cb_cls, nym, method_name, env,
921 data, data_size);
922 } while (0);
923
924 if (NULL != env)
925 GNUNET_PSYC_env_destroy (env);
926 if (NULL != entry_pmsg)
927 GNUNET_free (entry_pmsg);
928}
929
930
931static void
932handle_guest_enter_ack (void *cls,
933 const struct GNUNET_PSYC_CountersResultMessage *cres)
934{
935 struct GNUNET_SOCIAL_Guest *gst = cls;
936
937 int32_t result = ntohl (cres->result_code);
938 if (NULL != gst->enter_cb)
939 gst->enter_cb (gst->cb_cls, result, &gst->plc.pub_key,
940 GNUNET_ntohll (cres->max_message_id));
941}
942
943
944static int
945check_guest_enter_decision (void *cls,
946 const struct GNUNET_PSYC_JoinDecisionMessage *dcsn)
947{
948 return GNUNET_OK;
949}
950
951
952static void
953handle_guest_enter_decision (void *cls,
954 const struct GNUNET_PSYC_JoinDecisionMessage *dcsn)
955{
956 struct GNUNET_SOCIAL_Guest *gst = cls;
957
958 struct GNUNET_PSYC_Message *pmsg = NULL;
959 if (ntohs (dcsn->header.size) > sizeof (*dcsn))
960 pmsg = (struct GNUNET_PSYC_Message *) GNUNET_MQ_extract_nested_mh (dcsn);
961
962 if (NULL != gst->entry_dcsn_cb)
963 gst->entry_dcsn_cb (gst->cb_cls, ntohl (dcsn->is_admitted), pmsg);
964}
965
966
967static int
968check_app_ego (void *cls,
969 const struct AppEgoMessage *emsg)
970{
971 return GNUNET_OK;
972}
973
974
975static void
976handle_app_ego (void *cls,
977 const struct AppEgoMessage *emsg)
978{
979 struct GNUNET_SOCIAL_App *app = cls;
980
981 uint16_t name_size = ntohs (emsg->header.size) - sizeof (*emsg);
982
983 struct GNUNET_HashCode ego_pub_hash;
984 GNUNET_CRYPTO_hash (&emsg->ego_pub_key, sizeof (emsg->ego_pub_key),
985 &ego_pub_hash);
986
987 struct GNUNET_SOCIAL_Ego *
988 ego = GNUNET_CONTAINER_multihashmap_get (app->egos, &ego_pub_hash);
989 if (NULL == ego)
990 {
991 ego = GNUNET_malloc (sizeof (*ego));
992 ego->pub_key = emsg->ego_pub_key;
993 ego->name = GNUNET_malloc (name_size);
994 GNUNET_memcpy (ego->name, &emsg[1], name_size);
995 }
996 else
997 {
998 ego->name = GNUNET_realloc (ego->name, name_size);
999 GNUNET_memcpy (ego->name, &emsg[1], name_size);
1000 }
1001
1002 GNUNET_CONTAINER_multihashmap_put (app->egos, &ego_pub_hash, ego,
1003 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1004
1005 if (NULL != app->ego_cb)
1006 app->ego_cb (app->cb_cls, ego, &ego->pub_key, ego->name);
1007}
1008
1009
1010static void
1011handle_app_ego_end (void *cls,
1012 const struct GNUNET_MessageHeader *msg)
1013{
1014 //struct GNUNET_SOCIAL_App *app = cls;
1015}
1016
1017
1018static int
1019check_app_place (void *cls,
1020 const struct AppPlaceMessage *pmsg)
1021{
1022 return GNUNET_OK;
1023}
1024
1025
1026static void
1027handle_app_place (void *cls,
1028 const struct AppPlaceMessage *pmsg)
1029{
1030 struct GNUNET_SOCIAL_App *app = cls;
1031
1032 if ((GNUNET_YES == pmsg->is_host && NULL == app->host_cb)
1033 || (GNUNET_NO == pmsg->is_host && NULL == app->guest_cb))
1034 return;
1035
1036 struct GNUNET_HashCode ego_pub_hash;
1037 GNUNET_CRYPTO_hash (&pmsg->ego_pub_key, sizeof (pmsg->ego_pub_key),
1038 &ego_pub_hash);
1039 struct GNUNET_SOCIAL_Ego *
1040 ego = GNUNET_CONTAINER_multihashmap_get (app->egos, &ego_pub_hash);
1041 if (NULL == ego)
1042 {
1043 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failure to obtain ego %s.\n",
1044 GNUNET_h2s (&ego_pub_hash));
1045 GNUNET_break (0);
1046 return;
1047 }
1048
1049 if (GNUNET_YES == pmsg->is_host)
1050 {
1051 if (NULL != app->host_cb) {
1052 struct GNUNET_SOCIAL_HostConnection *hconn = GNUNET_malloc (sizeof (*hconn));
1053 hconn->app = app;
1054 hconn->plc_msg = *pmsg;
1055 app->host_cb (app->cb_cls, hconn, ego, &pmsg->place_pub_key, pmsg->place_state);
1056 GNUNET_free (hconn);
1057 }
1058 }
1059 else if (NULL != app->guest_cb)
1060 {
1061 struct GNUNET_SOCIAL_GuestConnection *gconn = GNUNET_malloc (sizeof (*gconn));
1062 gconn->app = app;
1063 gconn->plc_msg = *pmsg;
1064 app->guest_cb (app->cb_cls, gconn, ego, &pmsg->place_pub_key, pmsg->place_state);
1065 GNUNET_free (gconn);
1066 }
1067}
1068
1069
1070static void
1071handle_app_place_end (void *cls,
1072 const struct GNUNET_MessageHeader *msg)
1073{
1074 struct GNUNET_SOCIAL_App *app = cls;
1075
1076 if (NULL != app->connected_cb)
1077 app->connected_cb (app->cb_cls);
1078}
1079
1080
1081/**
1082 * Handler for a #GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE_ACK message received
1083 * from the social service.
1084 *
1085 * @param cls the place of type `struct GNUNET_SOCIAL_Place`
1086 * @param msg the message received from the service
1087 */
1088static void
1089handle_place_leave_ack (void *cls,
1090 const struct GNUNET_MessageHeader *msg)
1091{
1092 struct GNUNET_SOCIAL_Place *plc = cls;
1093
1094 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1095 "%s left place %p\n",
1096 plc->is_host ? "host" : "guest",
1097 plc);
1098 place_disconnect (plc);
1099}
1100
1101
1102/*** HOST ***/
1103
1104
1105static void
1106host_connect (struct GNUNET_SOCIAL_Host *hst);
1107
1108
1109static void
1110host_reconnect (void *cls)
1111{
1112 host_connect (cls);
1113}
1114
1115
1116/**
1117 * Host client disconnected from service.
1118 *
1119 * Reconnect after backoff period.
1120 */
1121static void
1122host_disconnected (void *cls, enum GNUNET_MQ_Error error)
1123{
1124 struct GNUNET_SOCIAL_Host *hst = cls;
1125 struct GNUNET_SOCIAL_Place *plc = &hst->plc;
1126
1127 LOG (GNUNET_ERROR_TYPE_DEBUG,
1128 "Host client disconnected (%d), re-connecting\n",
1129 (int) error);
1130 if (NULL != plc->tmit)
1131 {
1132 GNUNET_PSYC_transmit_destroy (plc->tmit);
1133 plc->tmit = NULL;
1134 }
1135 if (NULL != plc->mq)
1136 {
1137 GNUNET_MQ_destroy (plc->mq);
1138 plc->mq = NULL;
1139 }
1140
1141 plc->reconnect_task = GNUNET_SCHEDULER_add_delayed (plc->reconnect_delay,
1142 host_reconnect,
1143 hst);
1144 plc->reconnect_delay = GNUNET_TIME_STD_BACKOFF (plc->reconnect_delay);
1145}
1146
1147
1148static void
1149host_connect (struct GNUNET_SOCIAL_Host *hst)
1150{
1151 struct GNUNET_SOCIAL_Place *plc = &hst->plc;
1152
1153 struct GNUNET_MQ_MessageHandler handlers[] = {
1154 GNUNET_MQ_hd_fixed_size (host_enter_ack,
1155 GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK,
1156 struct HostEnterAck,
1157 hst),
1158 GNUNET_MQ_hd_fixed_size (place_leave_ack,
1159 GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE_ACK,
1160 struct GNUNET_MessageHeader,
1161 plc),
1162 GNUNET_MQ_hd_var_size (host_enter_request,
1163 GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST,
1164 struct GNUNET_PSYC_JoinRequestMessage,
1165 hst),
1166 GNUNET_MQ_hd_var_size (host_message,
1167 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE,
1168 struct GNUNET_PSYC_MessageHeader,
1169 hst),
1170 GNUNET_MQ_hd_fixed_size (place_message_ack,
1171 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK,
1172 struct GNUNET_MessageHeader,
1173 plc),
1174 GNUNET_MQ_hd_var_size (place_history_result,
1175 GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT,
1176 struct GNUNET_OperationResultMessage,
1177 plc),
1178 GNUNET_MQ_hd_var_size (place_state_result,
1179 GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT,
1180 struct GNUNET_OperationResultMessage,
1181 plc),
1182 GNUNET_MQ_hd_var_size (place_result,
1183 GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE,
1184 struct GNUNET_OperationResultMessage,
1185 plc),
1186 GNUNET_MQ_handler_end ()
1187 };
1188
1189 plc->mq = GNUNET_CLIENT_connect (plc->cfg, "social",
1190 handlers, host_disconnected, hst);
1191 GNUNET_assert (NULL != plc->mq);
1192 plc->tmit = GNUNET_PSYC_transmit_create (plc->mq);
1193
1194 GNUNET_MQ_send_copy (plc->mq, plc->connect_env);
1195}
1196
1197
1198/**
1199 * Enter a place as host.
1200 *
1201 * A place is created upon first entering, and it is active until permanently
1202 * left using GNUNET_SOCIAL_host_leave().
1203 *
1204 * @param app
1205 * Application handle.
1206 * @param ego
1207 * Identity of the host.
1208 * @param policy
1209 * Policy specifying entry and history restrictions for the place.
1210 * @param slicer
1211 * Slicer to handle incoming messages.
1212 * @param enter_cb
1213 * Function called when the place is entered and ready to use.
1214 * @param answer_door_cb
1215 * Function to handle new nyms that want to enter.
1216 * @param farewell_cb
1217 * Function to handle departing nyms.
1218 * @param cls
1219 * Closure for the callbacks.
1220 *
1221 * @return Handle for the host. This handle contains the pubkey.
1222 */
1223struct GNUNET_SOCIAL_Host *
1224GNUNET_SOCIAL_host_enter (const struct GNUNET_SOCIAL_App *app,
1225 const struct GNUNET_SOCIAL_Ego *ego,
1226 enum GNUNET_PSYC_Policy policy,
1227 struct GNUNET_PSYC_Slicer *slicer,
1228 GNUNET_SOCIAL_HostEnterCallback enter_cb,
1229 GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb,
1230 GNUNET_SOCIAL_FarewellCallback farewell_cb,
1231 void *cls)
1232{
1233 struct GNUNET_SOCIAL_Host *hst = GNUNET_malloc (sizeof (*hst));
1234 struct GNUNET_SOCIAL_Place *plc = &hst->plc;
1235
1236 plc->cfg = app->cfg;
1237 plc->is_host = GNUNET_YES;
1238 plc->slicer = slicer;
1239
1240 hst->enter_cb = enter_cb;
1241 hst->answer_door_cb = answer_door_cb;
1242 hst->farewell_cb = farewell_cb;
1243 hst->cb_cls = cls;
1244
1245 plc->op = GNUNET_OP_create ();
1246
1247 hst->slicer = GNUNET_PSYC_slicer_create ();
1248 GNUNET_PSYC_slicer_method_add (hst->slicer, "_notice_place_leave", NULL,
1249 host_recv_notice_place_leave_method,
1250 host_recv_notice_place_leave_modifier,
1251 NULL, host_recv_notice_place_leave_eom, hst);
1252
1253 uint16_t app_id_size = strlen (app->id) + 1;
1254 struct HostEnterRequest *hreq;
1255 plc->connect_env = GNUNET_MQ_msg_extra (hreq, app_id_size,
1256 GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER);
1257 hreq->policy = policy;
1258 hreq->ego_pub_key = ego->pub_key;
1259 GNUNET_memcpy (&hreq[1], app->id, app_id_size);
1260
1261 host_connect (hst);
1262 return hst;
1263}
1264
1265
1266/**
1267 * Reconnect to an already entered place as host.
1268 *
1269 * @param hconn
1270 * Host connection handle.
1271 * @see GNUNET_SOCIAL_app_connect() & GNUNET_SOCIAL_AppHostPlaceCallback()
1272 * @param slicer
1273 * Slicer to handle incoming messages.
1274 * @param enter_cb
1275 * Function called when the place is entered and ready to use.
1276 * @param answer_door_cb
1277 * Function to handle new nyms that want to enter.
1278 * @param farewell_cb
1279 * Function to handle departing nyms.
1280 * @param cls
1281 * Closure for the callbacks.
1282 *
1283 * @return Handle for the host.
1284 */
1285 struct GNUNET_SOCIAL_Host *
1286GNUNET_SOCIAL_host_enter_reconnect (struct GNUNET_SOCIAL_HostConnection *hconn,
1287 struct GNUNET_PSYC_Slicer *slicer,
1288 GNUNET_SOCIAL_HostEnterCallback enter_cb,
1289 GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb,
1290 GNUNET_SOCIAL_FarewellCallback farewell_cb,
1291 void *cls)
1292{
1293 struct GNUNET_SOCIAL_Host *hst = GNUNET_malloc (sizeof (*hst));
1294 struct GNUNET_SOCIAL_Place *plc = &hst->plc;
1295
1296 hst->enter_cb = enter_cb;
1297 hst->answer_door_cb = answer_door_cb;
1298 hst->farewell_cb = farewell_cb;
1299 hst->cb_cls = cls;
1300
1301 plc->cfg = hconn->app->cfg;
1302 plc->is_host = GNUNET_YES;
1303 plc->slicer = slicer;
1304 plc->pub_key = hconn->plc_msg.place_pub_key;
1305 plc->ego_pub_key = hconn->plc_msg.ego_pub_key;
1306
1307 plc->op = GNUNET_OP_create ();
1308
1309 hst->slicer = GNUNET_PSYC_slicer_create ();
1310 GNUNET_PSYC_slicer_method_add (hst->slicer, "_notice_place_leave", NULL,
1311 host_recv_notice_place_leave_method,
1312 host_recv_notice_place_leave_modifier,
1313 NULL, host_recv_notice_place_leave_eom, hst);
1314
1315 size_t app_id_size = strlen (hconn->app->id) + 1;
1316 struct HostEnterRequest *hreq;
1317 plc->connect_env = GNUNET_MQ_msg_extra (hreq, app_id_size,
1318 GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER);
1319 hreq->place_pub_key = hconn->plc_msg.place_pub_key;
1320 hreq->ego_pub_key = hconn->plc_msg.ego_pub_key;
1321 GNUNET_memcpy (&hreq[1], hconn->app->id, app_id_size);
1322
1323 host_connect (hst);
1324 return hst;
1325}
1326
1327
1328/**
1329 * Decision whether to admit @a nym into the place or refuse entry.
1330 *
1331 * @param hst
1332 * Host of the place.
1333 * @param nym
1334 * Handle for the entity that wanted to enter.
1335 * @param is_admitted
1336 * #GNUNET_YES if @a nym is admitted,
1337 * #GNUNET_NO if @a nym is refused entry,
1338 * #GNUNET_SYSERR if we cannot answer the request.
1339 * @param method_name
1340 * Method name for the rejection message.
1341 * @param env
1342 * Environment containing variables for the message, or NULL.
1343 * @param data
1344 * Data for the rejection message to send back.
1345 * @param data_size
1346 * Number of bytes in @a data for method.
1347 * @return #GNUNET_OK on success,
1348 * #GNUNET_SYSERR if the message is too large.
1349 */
1350int
1351GNUNET_SOCIAL_host_entry_decision (struct GNUNET_SOCIAL_Host *hst,
1352 struct GNUNET_SOCIAL_Nym *nym,
1353 int is_admitted,
1354 const struct GNUNET_PSYC_Message *entry_resp)
1355{
1356 struct GNUNET_SOCIAL_Place *plc = &hst->plc;
1357 struct GNUNET_PSYC_JoinDecisionMessage *dcsn;
1358 uint16_t entry_resp_size
1359 = (NULL != entry_resp) ? ntohs (entry_resp->header.size) : 0;
1360
1361 if (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < sizeof (*dcsn) + entry_resp_size)
1362 return GNUNET_SYSERR;
1363
1364 struct GNUNET_MQ_Envelope *
1365 env = GNUNET_MQ_msg_extra (dcsn, entry_resp_size,
1366 GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION);
1367 dcsn->is_admitted = htonl (is_admitted);
1368 dcsn->slave_pub_key = nym->pub_key;
1369
1370 if (0 < entry_resp_size)
1371 GNUNET_memcpy (&dcsn[1], entry_resp, entry_resp_size);
1372
1373 GNUNET_MQ_send (plc->mq, env);
1374 return GNUNET_OK;
1375}
1376
1377
1378/**
1379 * Throw @a nym out of the place.
1380 *
1381 * The @a nym reference will remain valid until the
1382 * #GNUNET_SOCIAL_FarewellCallback is invoked,
1383 * which should be very soon after this call.
1384 *
1385 * @param host
1386 * Host of the place.
1387 * @param nym
1388 * Handle for the entity to be ejected.
1389 * @param env
1390 * Environment for the message or NULL.
1391 */
1392void
1393GNUNET_SOCIAL_host_eject (struct GNUNET_SOCIAL_Host *hst,
1394 const struct GNUNET_SOCIAL_Nym *nym,
1395 struct GNUNET_PSYC_Environment *e)
1396{
1397 struct GNUNET_PSYC_Environment *env = e;
1398 if (NULL == env)
1399 env = GNUNET_PSYC_env_create ();
1400 GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
1401 "_nym", &nym->pub_key, sizeof (nym->pub_key));
1402 GNUNET_SOCIAL_host_announce (hst, "_notice_place_leave", env, NULL, NULL,
1403 GNUNET_SOCIAL_ANNOUNCE_NONE);
1404 if (NULL == e)
1405 GNUNET_PSYC_env_destroy (env);
1406}
1407
1408
1409/**
1410 * Get the public key of @a ego.
1411 *
1412 * @param ego
1413 * Ego.
1414 *
1415 * @return Public key of ego.
1416 */
1417const struct GNUNET_CRYPTO_EcdsaPublicKey *
1418GNUNET_SOCIAL_ego_get_pub_key (const struct GNUNET_SOCIAL_Ego *ego)
1419{
1420 return &ego->pub_key;
1421}
1422
1423
1424/**
1425 * Get the hash of the public key of @a ego.
1426 *
1427 * @param ego
1428 * Ego.
1429 *
1430 * @return Hash of the public key of @a ego.
1431 */
1432const struct GNUNET_HashCode *
1433GNUNET_SOCIAL_ego_get_pub_key_hash (const struct GNUNET_SOCIAL_Ego *ego)
1434{
1435 return &ego->pub_key_hash;
1436}
1437
1438
1439/**
1440 * Get the name of @a ego.
1441 *
1442 * @param ego
1443 * Ego.
1444 *
1445 * @return Public key of @a ego.
1446 */
1447const char *
1448GNUNET_SOCIAL_ego_get_name (const struct GNUNET_SOCIAL_Ego *ego)
1449{
1450 return ego->name;
1451}
1452
1453
1454/**
1455 * Get the public key of @a nym.
1456 *
1457 * Suitable, for example, to be used with GNUNET_SOCIAL_zone_add_nym().
1458 *
1459 * @param nym
1460 * Pseudonym.
1461 *
1462 * @return Public key of @a nym.
1463 */
1464const struct GNUNET_CRYPTO_EcdsaPublicKey *
1465GNUNET_SOCIAL_nym_get_pub_key (const struct GNUNET_SOCIAL_Nym *nym)
1466{
1467 return &nym->pub_key;
1468}
1469
1470
1471/**
1472 * Get the hash of the public key of @a nym.
1473 *
1474 * @param nym
1475 * Pseudonym.
1476 *
1477 * @return Hash of the public key of @a nym.
1478 */
1479const struct GNUNET_HashCode *
1480GNUNET_SOCIAL_nym_get_pub_key_hash (const struct GNUNET_SOCIAL_Nym *nym)
1481{
1482 return &nym->pub_key_hash;
1483}
1484
1485
1486/**
1487 * Send a message to all nyms that are present in the place.
1488 *
1489 * This function is restricted to the host. Nyms can only send requests
1490 * to the host who can decide to relay it to everyone in the place.
1491 *
1492 * @param host Host of the place.
1493 * @param method_name Method to use for the announcement.
1494 * @param env Environment containing variables for the message and operations
1495 * on objects of the place. Can be NULL.
1496 * @param notify Function to call to get the payload of the announcement.
1497 * @param notify_cls Closure for @a notify.
1498 * @param flags Flags for this announcement.
1499 *
1500 * @return NULL on error (announcement already in progress?).
1501 */
1502struct GNUNET_SOCIAL_Announcement *
1503GNUNET_SOCIAL_host_announce (struct GNUNET_SOCIAL_Host *hst,
1504 const char *method_name,
1505 const struct GNUNET_PSYC_Environment *env,
1506 GNUNET_PSYC_TransmitNotifyData notify_data,
1507 void *notify_data_cls,
1508 enum GNUNET_SOCIAL_AnnounceFlags flags)
1509{
1510 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1511 "PSYC_transmit_message for host, method: %s\n",
1512 method_name);
1513 if (GNUNET_OK ==
1514 GNUNET_PSYC_transmit_message (hst->plc.tmit, method_name, env,
1515 NULL, notify_data, notify_data_cls, flags))
1516 return (struct GNUNET_SOCIAL_Announcement *) hst->plc.tmit;
1517 else
1518 return NULL;
1519}
1520
1521
1522/**
1523 * Resume transmitting announcement.
1524 *
1525 * @param a
1526 * The announcement to resume.
1527 */
1528void
1529GNUNET_SOCIAL_host_announce_resume (struct GNUNET_SOCIAL_Announcement *a)
1530{
1531 GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) a);
1532}
1533
1534
1535/**
1536 * Cancel announcement.
1537 *
1538 * @param a
1539 * The announcement to cancel.
1540 */
1541void
1542GNUNET_SOCIAL_host_announce_cancel (struct GNUNET_SOCIAL_Announcement *a)
1543{
1544 GNUNET_PSYC_transmit_cancel ((struct GNUNET_PSYC_TransmitHandle *) a);
1545}
1546
1547
1548/**
1549 * Obtain handle for a hosted place.
1550 *
1551 * The returned handle can be used to access the place API.
1552 *
1553 * @param host Handle for the host.
1554 *
1555 * @return Handle for the hosted place, valid as long as @a host is valid.
1556 */
1557struct GNUNET_SOCIAL_Place *
1558GNUNET_SOCIAL_host_get_place (struct GNUNET_SOCIAL_Host *hst)
1559{
1560 return &hst->plc;
1561}
1562
1563
1564/**
1565 * Disconnect from a home.
1566 *
1567 * Invalidates host handle.
1568 *
1569 * @param hst
1570 * The host to disconnect.
1571 */
1572void
1573GNUNET_SOCIAL_host_disconnect (struct GNUNET_SOCIAL_Host *hst,
1574 GNUNET_ContinuationCallback disconnect_cb,
1575 void *cls)
1576{
1577 struct GNUNET_SOCIAL_Place *plc = &hst->plc;
1578
1579 plc->disconnect_cb = disconnect_cb;
1580 plc->disconnect_cls = cls;
1581 place_disconnect (plc);
1582}
1583
1584
1585/**
1586 * Stop hosting the home.
1587 *
1588 * Sends a _notice_place_closing announcement to the home.
1589 * Invalidates host handle.
1590 *
1591 * @param hst
1592 * The host leaving.
1593 * @param env
1594 * Environment for the message or NULL.
1595 * _nym is set to @e nym regardless whether an @e env is provided.
1596 * @param disconnect_cb
1597 * Function called after the host left the place
1598 * and disconnected from the social service.
1599 * @param cls
1600 * Closure for @a disconnect_cb.
1601 */
1602void
1603GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *hst,
1604 const struct GNUNET_PSYC_Environment *env,
1605 GNUNET_ContinuationCallback disconnect_cb,
1606 void *cls)
1607{
1608 struct GNUNET_MQ_Envelope *envelope;
1609
1610 GNUNET_SOCIAL_host_announce (hst, "_notice_place_closing", env, NULL, NULL,
1611 GNUNET_SOCIAL_ANNOUNCE_NONE);
1612 hst->plc.disconnect_cb = disconnect_cb;
1613 hst->plc.disconnect_cls = cls;
1614 envelope = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE);
1615 GNUNET_MQ_send (hst->plc.mq,
1616 envelope);
1617}
1618
1619
1620/*** GUEST ***/
1621
1622
1623static void
1624guest_connect (struct GNUNET_SOCIAL_Guest *gst);
1625
1626
1627static void
1628guest_reconnect (void *cls)
1629{
1630 guest_connect (cls);
1631}
1632
1633
1634/**
1635 * Guest client disconnected from service.
1636 *
1637 * Reconnect after backoff period.
1638 */
1639static void
1640guest_disconnected (void *cls, enum GNUNET_MQ_Error error)
1641{
1642 struct GNUNET_SOCIAL_Guest *gst = cls;
1643 struct GNUNET_SOCIAL_Place *plc = &gst->plc;
1644
1645 LOG (GNUNET_ERROR_TYPE_DEBUG,
1646 "Guest client disconnected (%d), re-connecting\n",
1647 (int) error);
1648 if (NULL != plc->tmit)
1649 {
1650 GNUNET_PSYC_transmit_destroy (plc->tmit);
1651 plc->tmit = NULL;
1652 }
1653 if (NULL != plc->mq)
1654 {
1655 GNUNET_MQ_destroy (plc->mq);
1656 plc->mq = NULL;
1657 }
1658
1659 plc->reconnect_task = GNUNET_SCHEDULER_add_delayed (plc->reconnect_delay,
1660 guest_reconnect,
1661 gst);
1662 plc->reconnect_delay = GNUNET_TIME_STD_BACKOFF (plc->reconnect_delay);
1663}
1664
1665
1666static void
1667guest_connect (struct GNUNET_SOCIAL_Guest *gst)
1668{
1669 struct GNUNET_SOCIAL_Place *plc = &gst->plc;
1670
1671 struct GNUNET_MQ_MessageHandler handlers[] = {
1672 GNUNET_MQ_hd_fixed_size (guest_enter_ack,
1673 GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK,
1674 struct GNUNET_PSYC_CountersResultMessage,
1675 gst),
1676 GNUNET_MQ_hd_fixed_size (place_leave_ack,
1677 GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE_ACK,
1678 struct GNUNET_MessageHeader,
1679 plc),
1680 GNUNET_MQ_hd_var_size (guest_enter_decision,
1681 GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION,
1682 struct GNUNET_PSYC_JoinDecisionMessage,
1683 gst),
1684 GNUNET_MQ_hd_var_size (place_message,
1685 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE,
1686 struct GNUNET_PSYC_MessageHeader,
1687 plc),
1688 GNUNET_MQ_hd_fixed_size (place_message_ack,
1689 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK,
1690 struct GNUNET_MessageHeader,
1691 plc),
1692 GNUNET_MQ_hd_var_size (place_history_result,
1693 GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT,
1694 struct GNUNET_OperationResultMessage,
1695 plc),
1696 GNUNET_MQ_hd_var_size (place_state_result,
1697 GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT,
1698 struct GNUNET_OperationResultMessage,
1699 plc),
1700 GNUNET_MQ_hd_var_size (place_result,
1701 GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE,
1702 struct GNUNET_OperationResultMessage,
1703 plc),
1704 GNUNET_MQ_handler_end ()
1705 };
1706
1707 plc->mq = GNUNET_CLIENT_connect (plc->cfg, "social",
1708 handlers, guest_disconnected, gst);
1709 GNUNET_assert (NULL != plc->mq);
1710 plc->tmit = GNUNET_PSYC_transmit_create (plc->mq);
1711
1712 GNUNET_MQ_send_copy (plc->mq, plc->connect_env);
1713}
1714
1715
1716static struct GNUNET_MQ_Envelope *
1717guest_enter_request_create (const char *app_id,
1718 const struct GNUNET_CRYPTO_EcdsaPublicKey *ego_pub_key,
1719 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
1720 const struct GNUNET_PeerIdentity *origin,
1721 size_t relay_count,
1722 const struct GNUNET_PeerIdentity *relays,
1723 const struct GNUNET_PSYC_Message *join_msg)
1724{
1725 uint16_t app_id_size = strlen (app_id) + 1;
1726 uint16_t join_msg_size = ntohs (join_msg->header.size);
1727 uint16_t relay_size = relay_count * sizeof (*relays);
1728
1729 struct GuestEnterRequest *greq;
1730 struct GNUNET_MQ_Envelope *
1731 env = GNUNET_MQ_msg_extra (greq, app_id_size + relay_size + join_msg_size,
1732 GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER);
1733 greq->place_pub_key = *place_pub_key;
1734 greq->ego_pub_key = *ego_pub_key;
1735 greq->origin = *origin;
1736 greq->relay_count = htonl (relay_count);
1737
1738 char *p = (char *) &greq[1];
1739 GNUNET_memcpy (p, app_id, app_id_size);
1740 p += app_id_size;
1741
1742 if (0 < relay_size)
1743 {
1744 GNUNET_memcpy (p, relays, relay_size);
1745 p += relay_size;
1746 }
1747
1748 GNUNET_memcpy (p, join_msg, join_msg_size);
1749 return env;
1750}
1751
1752
1753/**
1754 * Request entry to a place as a guest.
1755 *
1756 * @param app
1757 * Application handle.
1758 * @param ego
1759 * Identity of the guest.
1760 * @param place_pub_key
1761 * Public key of the place to enter.
1762 * @param flags
1763 * Flags for the entry.
1764 * @param origin
1765 * Peer identity of the origin of the underlying multicast group.
1766 * @param relay_count
1767 * Number of elements in the @a relays array.
1768 * @param relays
1769 * Relays for the underlying multicast group.
1770 * @param method_name
1771 * Method name for the message.
1772 * @param env
1773 * Environment containing variables for the message, or NULL.
1774 * @param data
1775 * Payload for the message to give to the enter callback.
1776 * @param data_size
1777 * Number of bytes in @a data.
1778 * @param slicer
1779 * Slicer to use for processing incoming requests from guests.
1780 *
1781 * @return NULL on errors, otherwise handle for the guest.
1782 */
1783struct GNUNET_SOCIAL_Guest *
1784GNUNET_SOCIAL_guest_enter (const struct GNUNET_SOCIAL_App *app,
1785 const struct GNUNET_SOCIAL_Ego *ego,
1786 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
1787 enum GNUNET_PSYC_SlaveJoinFlags flags,
1788 const struct GNUNET_PeerIdentity *origin,
1789 uint32_t relay_count,
1790 const struct GNUNET_PeerIdentity *relays,
1791 const struct GNUNET_PSYC_Message *entry_msg,
1792 struct GNUNET_PSYC_Slicer *slicer,
1793 GNUNET_SOCIAL_GuestEnterCallback local_enter_cb,
1794 GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb,
1795 void *cls)
1796{
1797 struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst));
1798 struct GNUNET_SOCIAL_Place *plc = &gst->plc;
1799
1800 plc->ego_pub_key = ego->pub_key;
1801 plc->pub_key = *place_pub_key;
1802 plc->cfg = app->cfg;
1803 plc->is_host = GNUNET_NO;
1804 plc->slicer = slicer;
1805
1806 plc->op = GNUNET_OP_create ();
1807
1808 plc->connect_env
1809 = guest_enter_request_create (app->id, &ego->pub_key, &plc->pub_key,
1810 origin, relay_count, relays, entry_msg);
1811
1812 gst->enter_cb = local_enter_cb;
1813 gst->entry_dcsn_cb = entry_dcsn_cb;
1814 gst->cb_cls = cls;
1815
1816 guest_connect (gst);
1817 return gst;
1818}
1819
1820
1821/**
1822 * Request entry to a place by name as a guest.
1823 *
1824 * @param app
1825 * Application handle.
1826 * @param ego
1827 * Identity of the guest.
1828 * @param gns_name
1829 * GNS name of the place to enter. Either in the form of
1830 * 'room.friend.gnu', or 'NYMPUBKEY.zkey'. This latter case refers to
1831 * the 'PLACE' record of the empty label ("+") in the GNS zone with the
1832 * nym's public key 'NYMPUBKEY', and can be used to request entry to a
1833 * pseudonym's place directly.
1834 * @param password
1835 * Password to decrypt the record, or NULL for cleartext records.
1836 * @param join_msg
1837 * Entry request message or NULL.
1838 * @param slicer
1839 * Slicer to use for processing incoming requests from guests.
1840 * @param local_enter_cb
1841 * Called upon connection established to the social service.
1842 * @param entry_decision_cb
1843 * Called upon receiving entry decision.
1844 *
1845 * @return NULL on errors, otherwise handle for the guest.
1846 */
1847struct GNUNET_SOCIAL_Guest *
1848GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_SOCIAL_App *app,
1849 const struct GNUNET_SOCIAL_Ego *ego,
1850 const char *gns_name,
1851 const char *password,
1852 const struct GNUNET_PSYC_Message *join_msg,
1853 struct GNUNET_PSYC_Slicer *slicer,
1854 GNUNET_SOCIAL_GuestEnterCallback local_enter_cb,
1855 GNUNET_SOCIAL_EntryDecisionCallback entry_decision_cb,
1856 void *cls)
1857{
1858 struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst));
1859 struct GNUNET_SOCIAL_Place *plc = &gst->plc;
1860
1861 if (NULL == password)
1862 password = "";
1863
1864 uint16_t app_id_size = strlen (app->id) + 1;
1865 uint16_t gns_name_size = strlen (gns_name) + 1;
1866 uint16_t password_size = strlen (password) + 1;
1867
1868 uint16_t join_msg_size = 0;
1869 if (NULL != join_msg)
1870 join_msg_size = ntohs (join_msg->header.size);
1871
1872 struct GuestEnterByNameRequest *greq;
1873 plc->connect_env
1874 = GNUNET_MQ_msg_extra (greq, app_id_size + gns_name_size
1875 + password_size + join_msg_size,
1876 GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME);
1877
1878 greq->ego_pub_key = ego->pub_key;
1879
1880 char *p = (char *) &greq[1];
1881 GNUNET_memcpy (p, app->id, app_id_size);
1882 p += app_id_size;
1883 GNUNET_memcpy (p, gns_name, gns_name_size);
1884 p += gns_name_size;
1885 GNUNET_memcpy (p, password, password_size);
1886 p += password_size;
1887 if (NULL != join_msg)
1888 GNUNET_memcpy (p, join_msg, join_msg_size);
1889
1890 plc->ego_pub_key = ego->pub_key;
1891 plc->cfg = app->cfg;
1892 plc->is_host = GNUNET_NO;
1893 plc->slicer = slicer;
1894
1895 plc->op = GNUNET_OP_create ();
1896
1897 gst->enter_cb = local_enter_cb;
1898 gst->entry_dcsn_cb = entry_decision_cb;
1899 gst->cb_cls = cls;
1900
1901 guest_connect (gst);
1902 return gst;
1903}
1904
1905
1906struct ReconnectContext
1907{
1908 struct GNUNET_SOCIAL_Guest *guest;
1909 int *result;
1910 int64_t *max_message_id;
1911 GNUNET_SOCIAL_GuestEnterCallback enter_cb;
1912 void *enter_cls;
1913};
1914
1915
1916static void
1917guest_enter_reconnect_cb (void *cls,
1918 int result,
1919 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
1920 uint64_t max_message_id)
1921{
1922 struct ReconnectContext *reconnect_ctx = cls;
1923
1924 GNUNET_assert (NULL != reconnect_ctx);
1925 reconnect_ctx->result = GNUNET_new (int);
1926 *(reconnect_ctx->result) = result;
1927 reconnect_ctx->max_message_id = GNUNET_new (int64_t);
1928 *(reconnect_ctx->max_message_id) = max_message_id;
1929}
1930
1931
1932static void
1933guest_entry_dcsn_reconnect_cb (void *cls,
1934 int is_admitted,
1935 const struct GNUNET_PSYC_Message *entry_resp)
1936{
1937 struct ReconnectContext *reconnect_ctx = cls;
1938 struct GNUNET_SOCIAL_Guest *gst = reconnect_ctx->guest;
1939
1940 GNUNET_assert (NULL != reconnect_ctx);
1941 GNUNET_assert (NULL != reconnect_ctx->result);
1942 GNUNET_assert (NULL != reconnect_ctx->max_message_id);
1943 if (GNUNET_YES != is_admitted)
1944 {
1945 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1946 "Guest was rejected after calling "
1947 "GNUNET_SOCIAL_guest_enter_reconnect ()\n");
1948 }
1949 else if (NULL != reconnect_ctx->enter_cb)
1950 {
1951 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1952 "guest reconnected!\n");
1953 reconnect_ctx->enter_cb (reconnect_ctx->enter_cls,
1954 *(reconnect_ctx->result),
1955 &gst->plc.pub_key,
1956 *(reconnect_ctx->max_message_id));
1957 }
1958 GNUNET_free (reconnect_ctx->result);
1959 GNUNET_free (reconnect_ctx->max_message_id);
1960 GNUNET_free (reconnect_ctx);
1961}
1962
1963
1964/**
1965 * Reconnect to an already entered place as guest.
1966 *
1967 * @param gconn
1968 * Guest connection handle.
1969 * @see GNUNET_SOCIAL_app_connect() & GNUNET_SOCIAL_AppGuestPlaceCallback()
1970 * @param flags
1971 * Flags for the entry.
1972 * @param slicer
1973 * Slicer to use for processing incoming requests from guests.
1974 * @param enter_cb
1975 * Called upon re-entering is complete.
1976 * @param entry_decision_cb
1977 * Called upon receiving entry decision.
1978 *
1979 * @return NULL on errors, otherwise handle for the guest.
1980 */
1981struct GNUNET_SOCIAL_Guest *
1982GNUNET_SOCIAL_guest_enter_reconnect (struct GNUNET_SOCIAL_GuestConnection *gconn,
1983 enum GNUNET_PSYC_SlaveJoinFlags flags,
1984 struct GNUNET_PSYC_Slicer *slicer,
1985 GNUNET_SOCIAL_GuestEnterCallback enter_cb,
1986 void *cls)
1987{
1988 struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst));
1989 struct GNUNET_SOCIAL_Place *plc = &gst->plc;
1990 struct ReconnectContext *reconnect_ctx;
1991
1992 uint16_t app_id_size = strlen (gconn->app->id) + 1;
1993 struct GuestEnterRequest *greq;
1994 plc->connect_env
1995 = GNUNET_MQ_msg_extra (greq, app_id_size,
1996 GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER);
1997 greq->ego_pub_key = gconn->plc_msg.ego_pub_key;
1998 greq->place_pub_key = gconn->plc_msg.place_pub_key;
1999 greq->flags = htonl (flags);
2000
2001 GNUNET_memcpy (&greq[1], gconn->app->id, app_id_size);
2002
2003 plc->cfg = gconn->app->cfg;
2004 plc->is_host = GNUNET_NO;
2005 plc->slicer = slicer;
2006 plc->pub_key = gconn->plc_msg.place_pub_key;
2007 plc->ego_pub_key = gconn->plc_msg.ego_pub_key;
2008
2009 reconnect_ctx = GNUNET_new (struct ReconnectContext);
2010 reconnect_ctx->guest = gst;
2011 reconnect_ctx->enter_cb = enter_cb;
2012 reconnect_ctx->enter_cls = cls;
2013
2014 plc->op = GNUNET_OP_create ();
2015 gst->enter_cb = &guest_enter_reconnect_cb;
2016 gst->entry_dcsn_cb = &guest_entry_dcsn_reconnect_cb;
2017 gst->cb_cls = reconnect_ctx;
2018
2019 guest_connect (gst);
2020 return gst;
2021}
2022
2023
2024/**
2025 * Talk to the host of the place.
2026 *
2027 * @param place
2028 * Place where we want to talk to the host.
2029 * @param method_name
2030 * Method to invoke on the host.
2031 * @param env
2032 * Environment containing variables for the message, or NULL.
2033 * @param notify_data
2034 * Function to use to get the payload for the method.
2035 * @param notify_data_cls
2036 * Closure for @a notify_data.
2037 * @param flags
2038 * Flags for the message being sent.
2039 *
2040 * @return NULL if we are already trying to talk to the host,
2041 * otherwise handle to cancel the request.
2042 */
2043struct GNUNET_SOCIAL_TalkRequest *
2044GNUNET_SOCIAL_guest_talk (struct GNUNET_SOCIAL_Guest *gst,
2045 const char *method_name,
2046 const struct GNUNET_PSYC_Environment *env,
2047 GNUNET_PSYC_TransmitNotifyData notify_data,
2048 void *notify_data_cls,
2049 enum GNUNET_SOCIAL_TalkFlags flags)
2050{
2051 struct GNUNET_SOCIAL_Place *plc = &gst->plc;
2052 GNUNET_assert (NULL != plc->tmit);
2053
2054 if (GNUNET_OK ==
2055 GNUNET_PSYC_transmit_message (plc->tmit, method_name, env,
2056 NULL, notify_data, notify_data_cls, flags))
2057 return (struct GNUNET_SOCIAL_TalkRequest *) plc->tmit;
2058 else
2059 return NULL;
2060}
2061
2062
2063/**
2064 * Resume talking to the host of the place.
2065 *
2066 * @param tr
2067 * Talk request to resume.
2068 */
2069void
2070GNUNET_SOCIAL_guest_talk_resume (struct GNUNET_SOCIAL_TalkRequest *tr)
2071{
2072 GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) tr);
2073}
2074
2075
2076/**
2077 * Cancel talking to the host of the place.
2078 *
2079 * @param tr
2080 * Talk request to cancel.
2081 */
2082void
2083GNUNET_SOCIAL_guest_talk_cancel (struct GNUNET_SOCIAL_TalkRequest *tr)
2084{
2085 GNUNET_PSYC_transmit_cancel ( (struct GNUNET_PSYC_TransmitHandle *) tr);
2086}
2087
2088
2089/**
2090 * Disconnect from a place.
2091 *
2092 * Invalidates guest handle.
2093 *
2094 * @param gst
2095 * The guest to disconnect.
2096 */
2097void
2098GNUNET_SOCIAL_guest_disconnect (struct GNUNET_SOCIAL_Guest *gst,
2099 GNUNET_ContinuationCallback disconnect_cb,
2100 void *cls)
2101{
2102 struct GNUNET_SOCIAL_Place *plc = &gst->plc;
2103
2104 plc->disconnect_cb = disconnect_cb;
2105 plc->disconnect_cls = cls;
2106 place_disconnect (plc);
2107}
2108
2109
2110/**
2111 * Leave a place temporarily or permanently.
2112 *
2113 * Notifies the owner of the place about leaving, and destroys the place handle.
2114 *
2115 * @param place
2116 * Place to leave.
2117 * @param keep_active
2118 * Keep place active after last application disconnected.
2119 * #GNUNET_YES or #GNUNET_NO
2120 * @param env
2121 * Optional environment for the leave message if @a keep_active
2122 * is #GNUNET_NO. NULL if not needed.
2123 * @param leave_cb
2124 * Called upon disconnecting from the social service.
2125 */
2126void
2127GNUNET_SOCIAL_guest_leave (struct GNUNET_SOCIAL_Guest *gst,
2128 struct GNUNET_PSYC_Environment *env,
2129 GNUNET_ContinuationCallback disconnect_cb,
2130 void *cls)
2131{
2132 struct GNUNET_MQ_Envelope *envelope;
2133
2134 GNUNET_SOCIAL_guest_talk (gst, "_notice_place_leave", env, NULL, NULL,
2135 GNUNET_SOCIAL_TALK_NONE);
2136 gst->plc.disconnect_cb = disconnect_cb;
2137 gst->plc.disconnect_cls = cls;
2138 envelope = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE);
2139 GNUNET_MQ_send (gst->plc.mq,
2140 envelope);
2141}
2142
2143
2144/**
2145 * Obtain handle for a place entered as guest.
2146 *
2147 * The returned handle can be used to access the place API.
2148 *
2149 * @param guest Handle for the guest.
2150 *
2151 * @return Handle for the place, valid as long as @a guest is valid.
2152 */
2153struct GNUNET_SOCIAL_Place *
2154GNUNET_SOCIAL_guest_get_place (struct GNUNET_SOCIAL_Guest *gst)
2155{
2156 return &gst->plc;
2157}
2158
2159
2160/**
2161 * Obtain the public key of a place.
2162 *
2163 * @param plc
2164 * Place.
2165 *
2166 * @return Public key of the place.
2167 */
2168const struct GNUNET_CRYPTO_EddsaPublicKey *
2169GNUNET_SOCIAL_place_get_pub_key (const struct GNUNET_SOCIAL_Place *plc)
2170{
2171 return &plc->pub_key;
2172}
2173
2174
2175/**
2176 * Set message processing @a flags for a @a method_prefix.
2177 *
2178 * @param plc
2179 * Place.
2180 * @param method_prefix
2181 * Method prefix @a flags apply to.
2182 * @param flags
2183 * The flags that apply to a matching @a method_prefix.
2184 */
2185void
2186GNUNET_SOCIAL_place_msg_proc_set (struct GNUNET_SOCIAL_Place *plc,
2187 const char *method_prefix,
2188 enum GNUNET_SOCIAL_MsgProcFlags flags)
2189{
2190 GNUNET_assert (NULL != method_prefix);
2191 struct MsgProcRequest *mpreq;
2192 uint16_t method_size = strnlen (method_prefix,
2193 GNUNET_MAX_MESSAGE_SIZE
2194 - sizeof (*mpreq)) + 1;
2195 GNUNET_assert ('\0' == method_prefix[method_size - 1]);
2196
2197 struct GNUNET_MQ_Envelope *
2198 env = GNUNET_MQ_msg_extra (mpreq, method_size,
2199 GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_SET);
2200 mpreq->flags = htonl (flags);
2201 GNUNET_memcpy (&mpreq[1], method_prefix, method_size);
2202
2203 GNUNET_MQ_send (plc->mq, env);
2204}
2205
2206
2207/**
2208 * Clear all message processing flags previously set for this place.
2209 */
2210void
2211GNUNET_SOCIAL_place_msg_proc_clear (struct GNUNET_SOCIAL_Place *plc)
2212{
2213 struct GNUNET_MessageHeader *req;
2214 struct GNUNET_MQ_Envelope *
2215 env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_CLEAR);
2216
2217 GNUNET_MQ_send (plc->mq, env);
2218}
2219
2220
2221static struct GNUNET_SOCIAL_HistoryRequest *
2222place_history_replay (struct GNUNET_SOCIAL_Place *plc,
2223 uint64_t start_message_id,
2224 uint64_t end_message_id,
2225 uint64_t message_limit,
2226 const char *method_prefix,
2227 uint32_t flags,
2228 struct GNUNET_PSYC_Slicer *slicer,
2229 GNUNET_ResultCallback result_cb,
2230 void *cls)
2231{
2232 struct GNUNET_PSYC_HistoryRequestMessage *req;
2233 struct GNUNET_SOCIAL_HistoryRequest *hist = GNUNET_malloc (sizeof (*hist));
2234 hist->plc = plc;
2235 hist->slicer = slicer;
2236 hist->result_cb = result_cb;
2237 hist->cls = cls;
2238 hist->op_id = GNUNET_OP_add (plc->op, op_recv_history_result, hist, NULL);
2239
2240 GNUNET_assert (NULL != method_prefix);
2241 uint16_t method_size = strnlen (method_prefix,
2242 GNUNET_MAX_MESSAGE_SIZE
2243 - sizeof (*req)) + 1;
2244 GNUNET_assert ('\0' == method_prefix[method_size - 1]);
2245
2246 struct GNUNET_MQ_Envelope *
2247 env = GNUNET_MQ_msg_extra (req, method_size,
2248 GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY);
2249 req->start_message_id = GNUNET_htonll (start_message_id);
2250 req->end_message_id = GNUNET_htonll (end_message_id);
2251 req->message_limit = GNUNET_htonll (message_limit);
2252 req->flags = htonl (flags);
2253 req->op_id = GNUNET_htonll (hist->op_id);
2254 GNUNET_memcpy (&req[1], method_prefix, method_size);
2255
2256 GNUNET_MQ_send (plc->mq, env);
2257 return hist;
2258}
2259
2260
2261/**
2262 * Learn about the history of a place.
2263 *
2264 * Messages are returned through the @a slicer function
2265 * and have the #GNUNET_PSYC_MESSAGE_HISTORIC flag set.
2266 *
2267 * @param place
2268 * Place we want to learn more about.
2269 * @param start_message_id
2270 * First historic message we are interested in.
2271 * @param end_message_id
2272 * Last historic message we are interested in (inclusive).
2273 * @param method_prefix
2274 * Only retrieve messages with this method prefix.
2275 * @param flags
2276 * OR'ed GNUNET_PSYC_HistoryReplayFlags
2277 * @param slicer
2278 * Slicer to use for retrieved messages.
2279 * Can be the same as the slicer of the place.
2280 * @param result_cb
2281 * Function called after all messages retrieved.
2282 * NULL if not needed.
2283 * @param cls Closure for @a result_cb.
2284 */
2285struct GNUNET_SOCIAL_HistoryRequest *
2286GNUNET_SOCIAL_place_history_replay (struct GNUNET_SOCIAL_Place *plc,
2287 uint64_t start_message_id,
2288 uint64_t end_message_id,
2289 const char *method_prefix,
2290 uint32_t flags,
2291 struct GNUNET_PSYC_Slicer *slicer,
2292 GNUNET_ResultCallback result_cb,
2293 void *cls)
2294{
2295 return place_history_replay (plc, start_message_id, end_message_id, 0,
2296 method_prefix, flags, slicer, result_cb, cls);
2297}
2298
2299
2300/**
2301 * Learn about the history of a place.
2302 *
2303 * Sends messages through the slicer function of the place where
2304 * start_message_id <= message_id <= end_message_id.
2305 * The messages will have the #GNUNET_PSYC_MESSAGE_HISTORIC flag set.
2306 *
2307 * To get the latest message, use 0 for both the start and end message ID.
2308 *
2309 * @param place
2310 * Place we want to learn more about.
2311 * @param message_limit
2312 * Maximum number of historic messages we are interested in.
2313 * @param method_prefix
2314 * Only retrieve messages with this method prefix.
2315 * @param flags
2316 * OR'ed GNUNET_PSYC_HistoryReplayFlags
2317 * @param result_cb
2318 * Function called after all messages retrieved.
2319 * NULL if not needed.
2320 * @param cls Closure for @a result_cb.
2321 */
2322struct GNUNET_SOCIAL_HistoryRequest *
2323GNUNET_SOCIAL_place_history_replay_latest (struct GNUNET_SOCIAL_Place *plc,
2324 uint64_t message_limit,
2325 const char *method_prefix,
2326 uint32_t flags,
2327 struct GNUNET_PSYC_Slicer *slicer,
2328 GNUNET_ResultCallback result_cb,
2329 void *cls)
2330{
2331 return place_history_replay (plc, 0, 0, message_limit, method_prefix, flags,
2332 slicer, result_cb, cls);
2333}
2334
2335
2336/**
2337 * Cancel learning about the history of a place.
2338 *
2339 * @param hist
2340 * History lesson to cancel.
2341 */
2342void
2343GNUNET_SOCIAL_place_history_replay_cancel (struct GNUNET_SOCIAL_HistoryRequest *hist)
2344{
2345 GNUNET_OP_remove (hist->plc->op, hist->op_id);
2346 GNUNET_free (hist);
2347}
2348
2349
2350/**
2351 * Request matching state variables.
2352 */
2353static struct GNUNET_SOCIAL_LookHandle *
2354place_state_get (struct GNUNET_SOCIAL_Place *plc,
2355 uint16_t type, const char *name,
2356 GNUNET_PSYC_StateVarCallback var_cb,
2357 GNUNET_ResultCallback result_cb, void *cls)
2358{
2359 struct GNUNET_PSYC_StateRequestMessage *req;
2360 struct GNUNET_SOCIAL_LookHandle *look = GNUNET_malloc (sizeof (*look));
2361 look->plc = plc;
2362 look->var_cb = var_cb;
2363 look->result_cb = result_cb;
2364 look->cls = cls;
2365 look->op_id = GNUNET_OP_add (plc->op, &op_recv_state_result, look, NULL);
2366
2367 GNUNET_assert (NULL != name);
2368 size_t name_size = strnlen (name, GNUNET_MAX_MESSAGE_SIZE
2369 - sizeof (*req)) + 1;
2370 struct GNUNET_MQ_Envelope *
2371 env = GNUNET_MQ_msg_extra (req, name_size, type);
2372 req->op_id = GNUNET_htonll (look->op_id);
2373 GNUNET_memcpy (&req[1], name, name_size);
2374
2375 GNUNET_MQ_send (plc->mq, env);
2376 return look;
2377}
2378
2379
2380/**
2381 * Look at a particular object in the place.
2382 *
2383 * The best matching object is returned (its name might be less specific than
2384 * what was requested).
2385 *
2386 * @param place
2387 * The place where to look.
2388 * @param full_name
2389 * Full name of the object.
2390 * @param value_size
2391 * Set to the size of the returned value.
2392 *
2393 * @return NULL if there is no such object at this place.
2394 */
2395struct GNUNET_SOCIAL_LookHandle *
2396GNUNET_SOCIAL_place_look_at (struct GNUNET_SOCIAL_Place *plc,
2397 const char *full_name,
2398 GNUNET_PSYC_StateVarCallback var_cb,
2399 GNUNET_ResultCallback result_cb,
2400 void *cls)
2401{
2402 return place_state_get (plc, GNUNET_MESSAGE_TYPE_PSYC_STATE_GET,
2403 full_name, var_cb, result_cb, cls);
2404}
2405
2406
2407/**
2408 * Look for objects in the place with a matching name prefix.
2409 *
2410 * @param place
2411 * The place where to look.
2412 * @param name_prefix
2413 * Look at objects with names beginning with this value.
2414 * @param var_cb
2415 * Function to call for each object found.
2416 * @param cls
2417 * Closure for callback function.
2418 *
2419 * @return Handle that can be used to stop looking at objects.
2420 */
2421struct GNUNET_SOCIAL_LookHandle *
2422GNUNET_SOCIAL_place_look_for (struct GNUNET_SOCIAL_Place *plc,
2423 const char *name_prefix,
2424 GNUNET_PSYC_StateVarCallback var_cb,
2425 GNUNET_ResultCallback result_cb,
2426 void *cls)
2427{
2428 return place_state_get (plc, GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX,
2429 name_prefix, var_cb, result_cb, cls);
2430}
2431
2432
2433/**
2434 * Cancel a state request operation.
2435 *
2436 * @param sr
2437 * Handle for the operation to cancel.
2438 */
2439void
2440GNUNET_SOCIAL_place_look_cancel (struct GNUNET_SOCIAL_LookHandle *look)
2441{
2442 GNUNET_OP_remove (look->plc->op, look->op_id);
2443 GNUNET_free (look);
2444}
2445
2446
2447static void
2448op_recv_zone_add_place_result (void *cls, int64_t result,
2449 const void *err_msg, uint16_t err_msg_size)
2450{
2451 LOG (GNUNET_ERROR_TYPE_DEBUG,
2452 "Received zone add place result: %" PRId64 ".\n", result);
2453
2454 struct ZoneAddPlaceHandle *add_plc = cls;
2455 if (NULL != add_plc->result_cb)
2456 add_plc->result_cb (add_plc->result_cls, result, err_msg, err_msg_size);
2457
2458 GNUNET_free (add_plc);
2459}
2460
2461
2462/**
2463 * Advertise @e place in the GNS zone of @e ego.
2464 *
2465 * @param app
2466 * Application handle.
2467 * @param ego
2468 * Ego.
2469 * @param place_pub_key
2470 * Public key of place to add.
2471 * @param name
2472 * The name for the PLACE record to put in the zone.
2473 * @param password
2474 * Password used to encrypt the record or NULL to keep it cleartext.
2475 * @param relay_count
2476 * Number of elements in the @a relays array.
2477 * @param relays
2478 * List of relays to put in the PLACE record to advertise
2479 * as entry points to the place in addition to the origin.
2480 * @param expiration_time
2481 * Expiration time of the record, use 0 to remove the record.
2482 * @param result_cb
2483 * Function called with the result of the operation.
2484 * @param result_cls
2485 * Closure for @a result_cb
2486 *
2487 * @return #GNUNET_OK if the request was sent,
2488 * #GNUNET_SYSERR on error, e.g. the name/password is too long.
2489 */
2490int
2491GNUNET_SOCIAL_zone_add_place (const struct GNUNET_SOCIAL_App *app,
2492 const struct GNUNET_SOCIAL_Ego *ego,
2493 const char *name,
2494 const char *password,
2495 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
2496 const struct GNUNET_PeerIdentity *origin,
2497 uint32_t relay_count,
2498 const struct GNUNET_PeerIdentity *relays,
2499 struct GNUNET_TIME_Absolute expiration_time,
2500 GNUNET_ResultCallback result_cb,
2501 void *result_cls)
2502{
2503 struct ZoneAddPlaceRequest *preq;
2504 size_t name_size = strlen (name) + 1;
2505 size_t password_size = strlen (password) + 1;
2506 size_t relay_size = relay_count * sizeof (*relays);
2507 size_t payload_size = name_size + password_size + relay_size;
2508
2509 if (GNUNET_MAX_MESSAGE_SIZE < sizeof (*preq) + payload_size)
2510 return GNUNET_SYSERR;
2511
2512 struct GNUNET_MQ_Envelope *
2513 env = GNUNET_MQ_msg_extra (preq, payload_size,
2514 GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_PLACE);
2515 preq->expiration_time = GNUNET_htonll (expiration_time.abs_value_us);
2516 preq->ego_pub_key = ego->pub_key;
2517 preq->place_pub_key = *place_pub_key;
2518 preq->origin = *origin;
2519 preq->relay_count = htonl (relay_count);
2520
2521 char *p = (char *) &preq[1];
2522 GNUNET_memcpy (p, name, name_size);
2523 p += name_size;
2524 GNUNET_memcpy (p, password, password_size);
2525 p += password_size;
2526 GNUNET_memcpy (p, relays, relay_size);
2527
2528 struct ZoneAddPlaceHandle * add_plc = GNUNET_malloc (sizeof (*add_plc));
2529 add_plc->result_cb = result_cb;
2530 add_plc->result_cls = result_cls;
2531
2532 preq->op_id = GNUNET_htonll (GNUNET_OP_add (app->op,
2533 op_recv_zone_add_place_result,
2534 add_plc, NULL));
2535
2536 GNUNET_MQ_send (app->mq, env);
2537 return GNUNET_OK;
2538}
2539
2540
2541static void
2542op_recv_zone_add_nym_result (void *cls, int64_t result,
2543 const void *err_msg, uint16_t err_msg_size)
2544{
2545 LOG (GNUNET_ERROR_TYPE_DEBUG,
2546 "Received zone add nym result: %" PRId64 ".\n", result);
2547
2548 struct ZoneAddNymHandle *add_nym = cls;
2549 if (NULL != add_nym->result_cb)
2550 add_nym->result_cb (add_nym->result_cls, result, err_msg, err_msg_size);
2551
2552 GNUNET_free (add_nym);
2553}
2554
2555
2556/**
2557 * Add nym to the GNS zone of @e ego.
2558 *
2559 * @param cfg
2560 * Configuration.
2561 * @param ego
2562 * Ego.
2563 * @param name
2564 * The name for the PKEY record to put in the zone.
2565 * @param nym_pub_key
2566 * Public key of nym to add.
2567 * @param expiration_time
2568 * Expiration time of the record, use 0 to remove the record.
2569 * @param result_cb
2570 * Function called with the result of the operation.
2571 * @param result_cls
2572 * Closure for @a result_cb
2573 *
2574 * @return #GNUNET_OK if the request was sent,
2575 * #GNUNET_SYSERR on error, e.g. the name is too long.
2576 */
2577int
2578GNUNET_SOCIAL_zone_add_nym (const struct GNUNET_SOCIAL_App *app,
2579 const struct GNUNET_SOCIAL_Ego *ego,
2580 const char *name,
2581 const struct GNUNET_CRYPTO_EcdsaPublicKey *nym_pub_key,
2582 struct GNUNET_TIME_Absolute expiration_time,
2583 GNUNET_ResultCallback result_cb,
2584 void *result_cls)
2585{
2586 struct ZoneAddNymRequest *nreq;
2587
2588 size_t name_size = strlen (name) + 1;
2589 if (GNUNET_MAX_MESSAGE_SIZE < sizeof (*nreq) + name_size)
2590 return GNUNET_SYSERR;
2591
2592 struct GNUNET_MQ_Envelope *
2593 env = GNUNET_MQ_msg_extra (nreq, name_size,
2594 GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_NYM);
2595 nreq->expiration_time = GNUNET_htonll (expiration_time.abs_value_us);
2596 nreq->ego_pub_key = ego->pub_key;
2597 nreq->nym_pub_key = *nym_pub_key;
2598 GNUNET_memcpy (&nreq[1], name, name_size);
2599
2600 struct ZoneAddNymHandle *add_nym = GNUNET_malloc (sizeof (*add_nym));
2601 add_nym->result_cb = result_cb;
2602 add_nym->result_cls = result_cls;
2603
2604 nreq->op_id = GNUNET_htonll (GNUNET_OP_add (app->op,
2605 op_recv_zone_add_nym_result,
2606 add_nym, NULL));
2607
2608 GNUNET_MQ_send (app->mq, env);
2609 return GNUNET_OK;
2610}
2611
2612
2613/*** APP ***/
2614
2615
2616static void
2617app_connect (struct GNUNET_SOCIAL_App *app);
2618
2619
2620static void
2621app_reconnect (void *cls)
2622{
2623 app_connect (cls);
2624}
2625
2626
2627/**
2628 * App client disconnected from service.
2629 *
2630 * Reconnect after backoff period.
2631 */
2632static void
2633app_disconnected (void *cls, enum GNUNET_MQ_Error error)
2634{
2635 struct GNUNET_SOCIAL_App *app = cls;
2636
2637 LOG (GNUNET_ERROR_TYPE_DEBUG,
2638 "App client disconnected (%d), re-connecting\n",
2639 (int) error);
2640 if (NULL != app->mq)
2641 {
2642 GNUNET_MQ_destroy (app->mq);
2643 app->mq = NULL;
2644 }
2645
2646 app->reconnect_task = GNUNET_SCHEDULER_add_delayed (app->reconnect_delay,
2647 app_reconnect,
2648 app);
2649 app->reconnect_delay = GNUNET_TIME_STD_BACKOFF (app->reconnect_delay);
2650}
2651
2652
2653static void
2654app_connect (struct GNUNET_SOCIAL_App *app)
2655{
2656 struct GNUNET_MQ_MessageHandler handlers[] = {
2657 GNUNET_MQ_hd_var_size (app_ego,
2658 GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO,
2659 struct AppEgoMessage,
2660 app),
2661 GNUNET_MQ_hd_fixed_size (app_ego_end,
2662 GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO_END,
2663 struct GNUNET_MessageHeader,
2664 app),
2665 GNUNET_MQ_hd_var_size (app_place,
2666 GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE,
2667 struct AppPlaceMessage,
2668 app),
2669 GNUNET_MQ_hd_fixed_size (app_place_end,
2670 GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE_END,
2671 struct GNUNET_MessageHeader,
2672 app),
2673 GNUNET_MQ_hd_var_size (app_result,
2674 GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE,
2675 struct GNUNET_OperationResultMessage,
2676 app),
2677 GNUNET_MQ_handler_end ()
2678 };
2679
2680 app->mq = GNUNET_CLIENT_connect (app->cfg, "social",
2681 handlers, app_disconnected, app);
2682 GNUNET_assert (NULL != app->mq);
2683 GNUNET_MQ_send_copy (app->mq, app->connect_env);
2684}
2685
2686
2687/**
2688 * Connect application to the social service.
2689 *
2690 * The @host_place_cb and @guest_place_cb functions are
2691 * initially called for each entered places,
2692 * then later each time a new place is entered with the current application ID.
2693 *
2694 * @param cfg
2695 * Configuration.
2696 * @param id
2697 * Application ID.
2698 * @param ego_cb
2699 * Function to notify about an available ego.
2700 * @param host_cb
2701 * Function to notify about a place entered as host.
2702 * @param guest_cb
2703 * Function to notify about a place entered as guest.
2704 * @param cls
2705 * Closure for the callbacks.
2706 *
2707 * @return Handle that can be used to stop listening.
2708 */
2709struct GNUNET_SOCIAL_App *
2710GNUNET_SOCIAL_app_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
2711 const char *id,
2712 GNUNET_SOCIAL_AppEgoCallback ego_cb,
2713 GNUNET_SOCIAL_AppHostPlaceCallback host_cb,
2714 GNUNET_SOCIAL_AppGuestPlaceCallback guest_cb,
2715 GNUNET_SOCIAL_AppConnectedCallback connected_cb,
2716 void *cls)
2717{
2718 uint16_t app_id_size = strnlen (id, GNUNET_SOCIAL_APP_MAX_ID_SIZE);
2719 if (GNUNET_SOCIAL_APP_MAX_ID_SIZE == app_id_size)
2720 return NULL;
2721 app_id_size++;
2722
2723 struct GNUNET_SOCIAL_App *app = GNUNET_malloc (sizeof *app);
2724 app->cfg = cfg;
2725 app->ego_cb = ego_cb;
2726 app->host_cb = host_cb;
2727 app->guest_cb = guest_cb;
2728 app->connected_cb = connected_cb;
2729 app->cb_cls = cls;
2730 app->egos = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
2731 app->op = GNUNET_OP_create ();
2732 app->id = GNUNET_malloc (app_id_size);
2733 GNUNET_memcpy (app->id, id, app_id_size);
2734
2735 struct AppConnectRequest *creq;
2736 app->connect_env = GNUNET_MQ_msg_extra (creq, app_id_size,
2737 GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT);
2738 GNUNET_memcpy (&creq[1], app->id, app_id_size);
2739
2740 app_connect (app);
2741 return app;
2742}
2743
2744
2745static void
2746app_cleanup (struct GNUNET_SOCIAL_App *app)
2747{
2748 if (NULL != app->mq)
2749 {
2750 GNUNET_MQ_destroy (app->mq);
2751 app->mq = NULL;
2752 }
2753 if (NULL != app->disconnect_cb)
2754 {
2755 app->disconnect_cb (app->disconnect_cls);
2756 app->disconnect_cb = NULL;
2757 }
2758 GNUNET_free (app);
2759}
2760
2761/**
2762 * Disconnect application.
2763 *
2764 * @param app
2765 * Application handle.
2766 * @param disconnect_cb
2767 * Disconnect callback.
2768 * @param disconnect_cls
2769 * Disconnect closure.
2770 */
2771void
2772GNUNET_SOCIAL_app_disconnect (struct GNUNET_SOCIAL_App *app,
2773 GNUNET_ContinuationCallback disconnect_cb,
2774 void *disconnect_cls)
2775{
2776 if (NULL == app) return;
2777
2778 app->disconnect_cb = disconnect_cb;
2779 app->disconnect_cls = disconnect_cls;
2780
2781 if (NULL != app->mq)
2782 {
2783 struct GNUNET_MQ_Envelope *env = GNUNET_MQ_get_last_envelope (app->mq);
2784 if (NULL != env)
2785 {
2786 GNUNET_MQ_notify_sent (env, (GNUNET_SCHEDULER_TaskCallback) app_cleanup, app);
2787 }
2788 else
2789 {
2790 app_cleanup (app);
2791 }
2792 }
2793 else
2794 {
2795 app_cleanup (app);
2796 }
2797}
2798
2799
2800/**
2801 * Detach application from a place.
2802 *
2803 * Removes the place from the entered places list for this application.
2804 * Note: this does not disconnect from the place.
2805 *
2806 * @see GNUNET_SOCIAL_host_disconnect() and GNUNET_SOCIAL_guest_disconnect()
2807 *
2808 * @param app
2809 * Application.
2810 * @param plc
2811 * Place.
2812 */
2813void
2814GNUNET_SOCIAL_app_detach (struct GNUNET_SOCIAL_App *app,
2815 struct GNUNET_SOCIAL_Place *plc)
2816{
2817 struct AppDetachRequest *dreq;
2818 struct GNUNET_MQ_Envelope *
2819 env = GNUNET_MQ_msg (dreq, GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH);
2820 dreq->place_pub_key = plc->pub_key;
2821 dreq->ego_pub_key = plc->ego_pub_key;
2822
2823 GNUNET_MQ_send (app->mq, env);
2824}
2825
2826
2827/* 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 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file social/test_social.c
22 * @brief Tests for the Social API.
23 * @author Gabor X Toth
24 */
25
26#include <inttypes.h>
27
28#include "platform.h"
29#include "gnunet_crypto_lib.h"
30#include "gnunet_common.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_testing_lib.h"
33#include "gnunet_psyc_util_lib.h"
34#include "gnunet_social_service.h"
35#include "gnunet_identity_service.h"
36
37#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
38
39#define DATA2ARG(data) data, sizeof (data)
40
41/**
42 * Return value from 'main'.
43 */
44int res;
45
46struct GNUNET_SOCIAL_App *app;
47const char *app_id = "test";
48
49/**
50 * Handle for task for timeout termination.
51 */
52struct GNUNET_SCHEDULER_Task *end_badly_task;
53
54const struct GNUNET_CONFIGURATION_Handle *cfg;
55
56struct GNUNET_PeerIdentity this_peer;
57
58struct GNUNET_IDENTITY_Handle *id;
59
60const struct GNUNET_IDENTITY_Ego *identity_host_ego;
61const struct GNUNET_IDENTITY_Ego *identity_guest_ego;
62
63const struct GNUNET_SOCIAL_Ego *host_ego;
64const struct GNUNET_SOCIAL_Ego *guest_ego;
65
66const char *host_name = "Host One";
67const char *guest_name = "Guest One";
68
69struct GNUNET_CRYPTO_EddsaPrivateKey *place_key;
70struct GNUNET_CRYPTO_EcdsaPrivateKey *guest_key;
71
72struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
73struct GNUNET_HashCode place_pub_hash;
74
75const struct GNUNET_CRYPTO_EcdsaPublicKey *guest_pub_key;
76const struct GNUNET_CRYPTO_EcdsaPublicKey *host_pub_key;
77
78struct GNUNET_PSYC_Slicer *host_slicer;
79struct GNUNET_PSYC_Slicer *guest_slicer;
80
81struct GNUNET_SOCIAL_Host *hst;
82struct GNUNET_SOCIAL_Guest *gst;
83
84struct GNUNET_SOCIAL_Place *hst_plc;
85struct GNUNET_SOCIAL_Place *gst_plc;
86
87struct GNUNET_SOCIAL_Nym *nym_eject;
88
89struct GuestEnterMessage
90{
91 struct GNUNET_PSYC_Message *msg;
92 const char *method_name;
93 struct GNUNET_PSYC_Environment *env;
94 void *data;
95 uint16_t data_size;
96} guest_enter_msg;
97
98struct TransmitClosure
99{
100 struct GNUNET_SOCIAL_Announcement *host_ann;
101 struct GNUNET_SOCIAL_TalkRequest *guest_talk;
102 struct GNUNET_PSYC_Environment *env;
103 char *data[16];
104 uint8_t data_delay[16];
105 uint8_t data_count;
106 uint8_t paused;
107 uint8_t n;
108} tmit;
109
110struct ResultClosure {
111 uint32_t n;
112} mod_foo_bar_rcls;
113
114uint8_t join_req_count;
115struct GNUNET_PSYC_Message *join_resp;
116
117uint32_t counter;
118
119uint8_t is_guest_nym_added = GNUNET_NO;
120uint8_t is_host_reconnected = GNUNET_NO;
121uint8_t is_guest_reconnected = GNUNET_NO;
122
123enum
124{
125 TEST_NONE = 0,
126 TEST_IDENTITIES_CREATE = 1,
127 TEST_HOST_ENTER = 2,
128 TEST_GUEST_ENTER = 3,
129 TEST_HOST_ANSWER_DOOR_REFUSE = 4,
130 TEST_GUEST_RECV_ENTRY_DCSN_REFUSE = 5,
131 TEST_HOST_ANSWER_DOOR_ADMIT = 6,
132 TEST_GUEST_RECV_ENTRY_DCSN_ADMIT = 7,
133 TEST_HOST_ANNOUNCE = 8,
134 TEST_HOST_ANNOUNCE_END = 9,
135 TEST_GUEST_TALK = 10,
136 TEST_HOST_ANNOUNCE2 = 11,
137 TEST_HOST_ANNOUNCE2_END = 12,
138 TEST_GUEST_HISTORY_REPLAY = 13,
139 TEST_GUEST_HISTORY_REPLAY_LATEST = 14,
140 TEST_GUEST_LOOK_AT = 15,
141 TEST_GUEST_LOOK_FOR = 16,
142 TEST_GUEST_LEAVE = 17,
143 TEST_ZONE_ADD_PLACE = 18,
144 TEST_GUEST_ENTER_BY_NAME = 19,
145 TEST_RECONNECT = 20,
146 TEST_GUEST_LEAVE2 = 21,
147 TEST_HOST_LEAVE = 22,
148} test;
149
150
151static void
152schedule_guest_leave (void *cls);
153
154
155static void
156host_answer_door (void *cls,
157 struct GNUNET_SOCIAL_Nym *nym,
158 const char *method_name,
159 struct GNUNET_PSYC_Environment *env,
160 const void *data,
161 size_t data_size);
162
163static void
164host_enter ();
165
166static void
167guest_init ();
168
169static void
170guest_enter ();
171
172static void
173guest_enter_by_name ();
174
175static void
176guest_talk ();
177
178static void
179host_announce2 ();
180
181
182/**
183 * Terminate the test case (failure).
184 *
185 * @param cls NULL
186 */
187static void
188end_badly (void *cls)
189{
190 end_badly_task = NULL;
191 GNUNET_SCHEDULER_shutdown ();
192 res = 2;
193 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
194 "Test FAILED.\n");
195}
196
197
198/**
199 * Terminate the test case (failure).
200 *
201 * @param cls NULL
202 */
203static void
204end_shutdown (void *cls)
205{
206 if (NULL != id)
207 {
208 GNUNET_IDENTITY_disconnect (id);
209 id = NULL;
210 }
211
212 if (NULL != guest_slicer)
213 {
214 GNUNET_PSYC_slicer_destroy (guest_slicer);
215 guest_slicer = NULL;
216 }
217
218 if (NULL != host_slicer)
219 {
220 GNUNET_PSYC_slicer_destroy (host_slicer);
221 host_slicer = NULL;
222 }
223 if (NULL != end_badly_task)
224 {
225 GNUNET_SCHEDULER_cancel (end_badly_task);
226 end_badly_task = NULL;
227 }
228 if (NULL != gst)
229 {
230 GNUNET_SOCIAL_guest_leave (gst, NULL, NULL, NULL);
231 gst = NULL;
232 gst_plc = NULL;
233 }
234 if (NULL != hst)
235 {
236 GNUNET_SOCIAL_host_leave (hst, NULL, NULL, NULL);
237 hst = NULL;
238 hst_plc = NULL;
239 }
240 GNUNET_SOCIAL_app_disconnect (app, NULL, NULL);
241}
242
243
244/**
245 * Terminate the test case (success).
246 *
247 * @param cls NULL
248 */
249static void
250end_normally (void *cls)
251{
252 GNUNET_SCHEDULER_shutdown ();
253 res = 0;
254 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Test PASSED.\n");
255}
256
257
258/**
259 * Finish the test case (successfully).
260 */
261static void
262end ()
263{
264 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
265 "Test #%u: Ending tests.\n", test);
266
267 if (end_badly_task != NULL)
268 {
269 GNUNET_SCHEDULER_cancel (end_badly_task);
270 end_badly_task = NULL;
271 }
272 GNUNET_SCHEDULER_add_now (&end_normally, NULL);
273}
274
275
276static void
277transmit_resume (void *cls)
278{
279 struct TransmitClosure *tmit = cls;
280
281 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
282 "Test #%u: Transmission resumed.\n", test);
283 if (NULL != tmit->host_ann)
284 GNUNET_SOCIAL_host_announce_resume (tmit->host_ann);
285 else
286 GNUNET_SOCIAL_guest_talk_resume (tmit->guest_talk);
287}
288
289
290static int
291notify_data (void *cls, uint16_t *data_size, void *data)
292{
293 struct TransmitClosure *tmit = cls;
294 if (NULL != tmit->env)
295 {
296 GNUNET_PSYC_env_destroy (tmit->env);
297 tmit->env = NULL;
298 }
299 if (0 == tmit->data_count)
300 {
301 *data_size = 0;
302 return GNUNET_YES;
303 }
304
305 uint16_t size = strlen (tmit->data[tmit->n]);
306 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
307 "Test #%u: Transmit notify data: %u bytes available, "
308 "processing fragment %u/%u (size %u).\n",
309 test, *data_size, tmit->n + 1, tmit->data_count, size);
310 if (*data_size < size)
311 {
312 *data_size = 0;
313 GNUNET_assert (0);
314 return GNUNET_SYSERR;
315 }
316
317 if (GNUNET_YES != tmit->paused && 0 < tmit->data_delay[tmit->n])
318 {
319 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
320 "Test #%u: Transmission paused.\n", test);
321 tmit->paused = GNUNET_YES;
322 GNUNET_SCHEDULER_add_delayed (
323 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
324 tmit->data_delay[tmit->n]),
325 &transmit_resume, tmit);
326 *data_size = 0;
327 return GNUNET_NO;
328 }
329 tmit->paused = GNUNET_NO;
330
331 *data_size = size;
332 GNUNET_memcpy (data, tmit->data[tmit->n], size);
333
334 return ++tmit->n < tmit->data_count ? GNUNET_NO : GNUNET_YES;
335}
336
337
338static void
339host_left ()
340{
341 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
342 "Test #%u: The host has left the place.\n", test);
343 end ();
344}
345
346
347static void
348schedule_host_leave (void *cls)
349{
350 test = TEST_HOST_LEAVE;
351 GNUNET_SOCIAL_host_leave (hst, NULL, &host_left, NULL);
352 hst = NULL;
353 hst_plc = NULL;
354}
355
356
357static void
358host_farewell2 (void *cls,
359 const struct GNUNET_SOCIAL_Nym *nym,
360 struct GNUNET_PSYC_Environment *env)
361{
362 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
363 "Nym left the place again.\n");
364 GNUNET_SCHEDULER_add_now (&schedule_host_leave, NULL);
365}
366
367
368static void
369host_reconnected (void *cls, int result,
370 const struct GNUNET_CRYPTO_EddsaPublicKey *home_pub_key,
371 uint64_t max_message_id)
372{
373 place_pub_key = *home_pub_key;
374 GNUNET_CRYPTO_hash (&place_pub_key, sizeof (place_pub_key), &place_pub_hash);
375 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
376 "Test #%u: Host reconnected to place %s\n",
377 test, GNUNET_h2s (&place_pub_hash));
378
379 is_host_reconnected = GNUNET_YES;
380 if (GNUNET_YES == is_guest_reconnected)
381 {
382 GNUNET_assert (NULL != gst);
383 GNUNET_SCHEDULER_add_now (&schedule_guest_leave, NULL);
384 }
385}
386
387
388static void
389guest_reconnected (void *cls, int result,
390 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
391 uint64_t max_message_id)
392{
393 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
394 "Test #%u: Guest reconnected to place: %d\n",
395 test, result);
396 GNUNET_assert (0 <= result);
397
398 is_guest_reconnected = GNUNET_YES;
399 if (GNUNET_YES == is_host_reconnected)
400 {
401 GNUNET_assert (NULL != gst);
402 GNUNET_SCHEDULER_add_now (&schedule_guest_leave, NULL);
403 }
404}
405
406
407static void
408app_connected (void *cls)
409{
410 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
411 "Test #%u: App connected: %p\n", test, cls);
412}
413
414
415static void
416app_recv_host (void *cls,
417 struct GNUNET_SOCIAL_HostConnection *hconn,
418 struct GNUNET_SOCIAL_Ego *ego,
419 const struct GNUNET_CRYPTO_EddsaPublicKey *host_pub_key,
420 enum GNUNET_SOCIAL_AppPlaceState place_state)
421{
422 struct GNUNET_HashCode host_pub_hash;
423
424 GNUNET_CRYPTO_hash (host_pub_key,
425 sizeof (*host_pub_key),
426 &host_pub_hash);
427
428 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
429 "Test #%u: Got app host place notification: %s\n",
430 test,
431 GNUNET_h2s (&host_pub_hash));
432
433 if (test == TEST_RECONNECT)
434 {
435 if (0 == memcmp (&place_pub_key, host_pub_key, sizeof (*host_pub_key)))
436 {
437 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
438 "Test #%u: Reconnecting to host place: %s\n",
439 test, GNUNET_h2s (&host_pub_hash));
440 hst = GNUNET_SOCIAL_host_enter_reconnect (hconn, host_slicer,
441 &host_reconnected,
442 &host_answer_door,
443 &host_farewell2,
444 NULL);
445 }
446 }
447}
448
449
450static void
451app_recv_guest (void *cls,
452 struct GNUNET_SOCIAL_GuestConnection *gconn,
453 struct GNUNET_SOCIAL_Ego *ego,
454 const struct GNUNET_CRYPTO_EddsaPublicKey *guest_pub_key,
455 enum GNUNET_SOCIAL_AppPlaceState place_state)
456{
457 struct GNUNET_HashCode guest_pub_hash;
458
459 GNUNET_CRYPTO_hash (guest_pub_key,
460 sizeof (*guest_pub_key),
461 &guest_pub_hash);
462
463 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
464 "Test #%u: Got app guest place notification: %s\n",
465 test, GNUNET_h2s (&guest_pub_hash));
466
467 if (test == TEST_RECONNECT)
468 {
469 if (0 == memcmp (&place_pub_key,
470 guest_pub_key,
471 sizeof (*guest_pub_key)))
472 {
473 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
474 "Test #%u: Reconnecting to guest place: %s\n",
475 test, GNUNET_h2s (&guest_pub_hash));
476 gst = GNUNET_SOCIAL_guest_enter_reconnect (gconn,
477 GNUNET_PSYC_SLAVE_JOIN_NONE,
478 guest_slicer,
479 &guest_reconnected,
480 NULL);
481 GNUNET_assert (NULL != gst);
482 }
483 }
484}
485
486
487static void
488enter_if_ready ()
489{
490 if (NULL == host_ego || NULL == guest_ego)
491 {
492 return;
493 }
494 host_enter ();
495 guest_init ();
496}
497
498
499static void
500app_recv_ego (void *cls,
501 struct GNUNET_SOCIAL_Ego *ego,
502 const struct GNUNET_CRYPTO_EcdsaPublicKey *ego_pub_key,
503 const char *name)
504{
505 char *ego_pub_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (ego_pub_key);
506 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
507 "Test #%u: Got app ego notification: %p %s %s\n",
508 test, ego, name, ego_pub_str);
509 GNUNET_free (ego_pub_str);
510
511 if (NULL != strstr (name, host_name))
512 {
513 host_ego = ego;
514 host_pub_key = ego_pub_key;
515 if (TEST_IDENTITIES_CREATE == test)
516 {
517 enter_if_ready ();
518 }
519 else
520 {
521 GNUNET_assert (TEST_RECONNECT == test);
522 }
523 }
524 else if (NULL != strstr (name, guest_name))
525 {
526 guest_ego = ego;
527 guest_pub_key = ego_pub_key;
528 if (TEST_IDENTITIES_CREATE == test)
529 {
530 enter_if_ready ();
531 }
532 else
533 {
534 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
535 "test = %d\n",
536 test);
537 GNUNET_assert (TEST_RECONNECT == test);
538 }
539 }
540}
541
542
543static void
544schedule_reconnect (void *cls)
545{
546 test = TEST_RECONNECT;
547 GNUNET_SOCIAL_host_disconnect (hst, NULL, NULL);
548 GNUNET_SOCIAL_guest_disconnect (gst, NULL, NULL);
549 hst = NULL;
550 gst = NULL;
551
552 GNUNET_SOCIAL_app_disconnect (app, NULL, NULL);
553 app = GNUNET_SOCIAL_app_connect (cfg, app_id,
554 &app_recv_ego,
555 &app_recv_host,
556 &app_recv_guest,
557 &app_connected,
558 NULL);
559}
560
561
562static void
563host_recv_zone_add_place_result (void *cls, int64_t result,
564 const void *data, uint16_t data_size)
565{
566 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
567 "Test #%u: Zone add place result: %" PRId64 " (%.*s).\n",
568 test, result, data_size, (const char *) data);
569 GNUNET_assert (GNUNET_YES == result);
570
571 GNUNET_assert (GNUNET_YES == is_guest_nym_added);
572 guest_enter_by_name ();
573}
574
575
576static void
577zone_add_place ()
578{
579 test = TEST_ZONE_ADD_PLACE;
580 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
581 "Test #%u: Adding place to zone.\n", test);
582
583 GNUNET_SOCIAL_zone_add_place (app, host_ego, "home", "let.me*in!",
584 &place_pub_key, &this_peer, 1, &this_peer,
585 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES),
586 host_recv_zone_add_place_result, app);
587}
588
589
590static void
591host_farewell (void *cls,
592 const struct GNUNET_SOCIAL_Nym *nym,
593 struct GNUNET_PSYC_Environment *env)
594{
595 const struct GNUNET_CRYPTO_EcdsaPublicKey *
596 nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym);
597
598 char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key);
599 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
600 "Test #%u: Farewell: nym %s (%s) has left the place.\n",
601 test, GNUNET_h2s (GNUNET_SOCIAL_nym_get_pub_key_hash (nym)), str);
602 GNUNET_free (str);
603 GNUNET_assert (1 == GNUNET_PSYC_env_get_count (env));
604 if (0 != memcmp (guest_pub_key, nym_key, sizeof (*nym_key)))
605 {
606 str = GNUNET_CRYPTO_ecdsa_public_key_to_string (guest_pub_key);
607 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
608 "Test #%u: Farewell: nym does not match guest: %s\n",
609 test, str);
610 GNUNET_free (str);
611 GNUNET_assert (0);
612 }
613 zone_add_place ();
614}
615
616
617static void
618guest_left (void *cls)
619{
620 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
621 "Test #%u: The guest has left the place.\n", test);
622}
623
624
625static void
626guest_leave ()
627{
628 if (test < TEST_RECONNECT)
629 test = TEST_GUEST_LEAVE;
630 else
631 test = TEST_GUEST_LEAVE2;
632
633 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
634 GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET,
635 "_notice_place_leave", DATA2ARG ("Leaving."));
636 GNUNET_SOCIAL_guest_leave (gst, env, &guest_left, NULL);
637 GNUNET_PSYC_env_destroy (env);
638 gst = NULL;
639 gst_plc = NULL;
640}
641
642
643static void
644schedule_guest_leave (void *cls)
645{
646 guest_leave ();
647}
648
649
650static void
651guest_look_for_result (void *cls,
652 int64_t result_code,
653 const void *data,
654 uint16_t data_size)
655{
656 struct ResultClosure *rcls = cls;
657 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
658 "Test #%u: guest_look_for_result: %" PRId64 "\n",
659 test, result_code);
660 GNUNET_assert (GNUNET_OK == result_code);
661 GNUNET_assert (6 == rcls->n);
662 GNUNET_free (rcls);
663 GNUNET_SCHEDULER_add_now (&schedule_guest_leave, NULL);
664}
665
666
667static void
668guest_look_for_var (void *cls,
669 const struct GNUNET_MessageHeader *mod,
670 const char *name,
671 const void *value,
672 uint32_t value_size,
673 uint32_t full_value_size)
674{
675 struct ResultClosure *rcls = cls;
676 rcls->n++;
677 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
678 "Test #%u: guest_look_for_var: %s\n%.*s\n",
679 test, name, value_size, (const char *) value);
680}
681
682
683static void
684guest_look_for ()
685{
686 test = TEST_GUEST_LOOK_FOR;
687 struct ResultClosure *rcls = GNUNET_malloc (sizeof (*rcls));
688 GNUNET_SOCIAL_place_look_for (gst_plc, "_foo", guest_look_for_var, guest_look_for_result, rcls);
689}
690
691
692static void
693guest_look_at_result (void *cls, int64_t result_code,
694 const void *data, uint16_t data_size)
695{
696 struct ResultClosure *rcls = cls;
697
698 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
699 "Test #%u: guest_look_at_result: %" PRId64 "\n",
700 test, result_code);
701 GNUNET_assert (GNUNET_OK == result_code);
702 GNUNET_assert (1 == rcls->n);
703 GNUNET_free (rcls);
704 guest_look_for ();
705}
706
707
708static void
709guest_look_at_var (void *cls,
710 const struct GNUNET_MessageHeader *mod,
711 const char *name,
712 const void *value,
713 uint32_t value_size,
714 uint32_t full_value_size)
715{
716 struct ResultClosure *rcls = cls;
717 rcls->n++;
718
719 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
720 "Test #%u: guest_look_at_var: %s\n%.*s\n",
721 test ,name, value_size, (const char *) value);
722}
723
724
725static void
726guest_look_at ()
727{
728 test = TEST_GUEST_LOOK_AT;
729 struct ResultClosure *rcls = GNUNET_malloc (sizeof (*rcls));
730 GNUNET_SOCIAL_place_look_at (gst_plc, "_foo_bar", guest_look_at_var, guest_look_at_result, rcls);
731}
732
733
734static void
735guest_recv_history_replay_latest_result (void *cls, int64_t result,
736 const void *data, uint16_t data_size)
737{
738 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
739 "Test #%u: Guest received latest history replay result "
740 "(%" PRIu32 " messages, %" PRId64 " fragments):\n"
741 "%.*s\n",
742 test, counter, result, data_size, (const char *) data);
743 //GNUNET_assert (2 == counter); /* message count */
744 //GNUNET_assert (7 == result); /* fragment count */
745
746 guest_look_at ();
747}
748
749
750static void
751guest_history_replay_latest ()
752{
753 test = TEST_GUEST_HISTORY_REPLAY_LATEST;
754 counter = 0;
755 GNUNET_SOCIAL_place_history_replay_latest (gst_plc, 3, "",
756 GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
757 guest_slicer,
758 &guest_recv_history_replay_latest_result,
759 NULL);
760}
761
762
763static void
764guest_recv_history_replay_result (void *cls, int64_t result,
765 const void *data, uint16_t data_size)
766{
767 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
768 "Test #%u: Guest received history replay result: %" PRId64 "\n"
769 "%.*s\n",
770 test, result, data_size, (const char *) data);
771// GNUNET_assert (2 == counter); /* message count */
772// GNUNET_assert (7 == result); /* fragment count */
773
774 guest_history_replay_latest ();
775}
776
777
778static void
779guest_history_replay ()
780{
781 test = TEST_GUEST_HISTORY_REPLAY;
782 counter = 0;
783 GNUNET_SOCIAL_place_history_replay (gst_plc, 1, 3, "",
784 GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
785 guest_slicer,
786 &guest_recv_history_replay_result,
787 NULL);
788}
789
790
791static void
792guest_recv_method (void *cls,
793 const struct GNUNET_PSYC_MessageHeader *msg,
794 const struct GNUNET_PSYC_MessageMethod *meth,
795 uint64_t message_id,
796 const char *method_name)
797{
798 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
799 "Test #%u: Guest received method for message ID %" PRIu64 ":\n"
800 "%s (flags: %x)\n",
801 test, message_id, method_name, ntohl (meth->flags));
802 /** @todo FIXME: check message */
803}
804
805
806static void
807guest_recv_modifier (void *cls,
808 const struct GNUNET_PSYC_MessageHeader *msg,
809 const struct GNUNET_MessageHeader *pmsg,
810 uint64_t message_id,
811 enum GNUNET_PSYC_Operator oper,
812 const char *name,
813 const void *value,
814 uint16_t value_size,
815 uint16_t full_value_size)
816{
817 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
818 "Test #%u: Guest received modifier for message ID %" PRIu64 ":\n"
819 "%c%s: %.*s (size: %u)\n",
820 test, message_id, oper, name, value_size, (const char *) value, value_size);
821 /** @todo FIXME: check modifier */
822}
823
824static void
825guest_recv_mod_foo_bar (void *cls,
826 const struct GNUNET_PSYC_MessageHeader *msg,
827 const struct GNUNET_MessageHeader *pmsg,
828 uint64_t message_id,
829 enum GNUNET_PSYC_Operator oper,
830 const char *name,
831 const void *value,
832 uint16_t value_size,
833 uint16_t full_value_size)
834{
835 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
836 "Test #%u: Guest received modifier matching _foo_bar for message ID %" PRIu64 ":\n"
837 "%c%s: %.*s (size: %u)\n",
838 test, message_id, oper, name, value_size, (const char *) value, value_size);
839 struct ResultClosure *rc = cls;
840 rc->n++;
841 /** @todo FIXME: check modifier */
842}
843
844
845static void
846guest_recv_data (void *cls,
847 const struct GNUNET_PSYC_MessageHeader *msg,
848 const struct GNUNET_MessageHeader *pmsg,
849 uint64_t message_id,
850 const void *data,
851 uint16_t data_size)
852{
853 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
854 "Test #%u: Guest received data for message ID %" PRIu64 ":\n"
855 "%.*s\n",
856 test, message_id, data_size, (const char *) data);
857 /** @todo FIXME: check data */
858}
859
860
861static void
862guest_recv_eom (void *cls,
863 const struct GNUNET_PSYC_MessageHeader *msg,
864 const struct GNUNET_MessageHeader *pmsg,
865 uint64_t message_id,
866 uint8_t is_cancelled)
867{
868 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
869 "Test #%u: Guest received end of message ID %" PRIu64
870 ", cancelled: %u\n",
871 test, message_id, is_cancelled);
872
873 switch (test)
874 {
875 case TEST_HOST_ANNOUNCE:
876 test = TEST_HOST_ANNOUNCE_END;
877 break;
878
879 case TEST_HOST_ANNOUNCE_END:
880 guest_talk ();
881 break;
882
883 case TEST_HOST_ANNOUNCE2:
884 test = TEST_HOST_ANNOUNCE2_END;
885 break;
886
887 case TEST_HOST_ANNOUNCE2_END:
888 guest_history_replay ();
889 break;
890
891 case TEST_GUEST_HISTORY_REPLAY:
892 case TEST_GUEST_HISTORY_REPLAY_LATEST:
893 counter++;
894 break;
895
896 default:
897 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "invalid test: %d\n", test);
898 GNUNET_assert (0);
899 }
900}
901
902
903static void
904host_recv_method (void *cls,
905 const struct GNUNET_PSYC_MessageHeader *msg,
906 const struct GNUNET_PSYC_MessageMethod *meth,
907 uint64_t message_id,
908 const char *method_name)
909{
910 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
911 "Test #%u: Host received method for message ID %" PRIu64 ":\n"
912 "%s\n",
913 test, message_id, method_name);
914 /** @todo FIXME: check message */
915}
916
917
918static void
919host_recv_modifier (void *cls,
920 const struct GNUNET_PSYC_MessageHeader *msg,
921 const struct GNUNET_MessageHeader *pmsg,
922 uint64_t message_id,
923 enum GNUNET_PSYC_Operator oper,
924 const char *name,
925 const void *value,
926 uint16_t value_size,
927 uint16_t full_value_size)
928{
929 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
930 "Test #%u: Host received modifier for message ID %" PRIu64 ":\n"
931 "%c%s: %.*s\n",
932 test, message_id, oper, name, value_size, (const char *) value);
933}
934
935
936static void
937host_recv_data (void *cls,
938 const struct GNUNET_PSYC_MessageHeader *msg,
939 const struct GNUNET_MessageHeader *pmsg,
940 uint64_t message_id,
941 const void *data,
942 uint16_t data_size)
943{
944 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
945 "Test #%u: Host received data for message ID %" PRIu64 ":\n"
946 "%.*s\n",
947 test, message_id, data_size, (const char *) data);
948}
949
950
951static void
952host_recv_eom (void *cls,
953 const struct GNUNET_PSYC_MessageHeader *msg,
954 const struct GNUNET_MessageHeader *pmsg,
955 uint64_t message_id,
956 uint8_t is_cancelled)
957{
958 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
959 "Test #%u: Host received end of message ID %" PRIu64
960 ", cancelled: %u\n",
961 test, message_id, is_cancelled);
962
963 switch (test)
964 {
965 case TEST_HOST_ANNOUNCE:
966 test = TEST_HOST_ANNOUNCE_END;
967 break;
968
969 case TEST_HOST_ANNOUNCE_END:
970 guest_talk ();
971 break;
972
973 case TEST_HOST_ANNOUNCE2:
974 test = TEST_HOST_ANNOUNCE2_END;
975 break;
976
977 case TEST_HOST_ANNOUNCE2_END:
978 guest_history_replay ();
979 break;
980
981 case TEST_GUEST_TALK:
982 host_announce2 ();
983 break;
984
985 default:
986 if (TEST_GUEST_LEAVE <= test)
987 break;
988 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid test: #%u\n", test);
989 GNUNET_assert (0);
990 }
991}
992
993
994static void
995guest_talk ()
996{
997 test = TEST_GUEST_TALK;
998
999 tmit = (struct TransmitClosure) {};
1000 tmit.env = GNUNET_PSYC_env_create ();
1001 GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN,
1002 "_bar_foo", DATA2ARG ("one two three"));
1003 GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN,
1004 "_bar_baz", DATA2ARG ("four five"));
1005 tmit.data[0] = "zzz xxx yyy ";
1006 tmit.data[1] = "zyx wvu tsr qpo.\n";
1007 tmit.data_delay[1] = 1;
1008 tmit.data[2] = "testing ten nine eight.\n";
1009 tmit.data_count = 3;
1010
1011 tmit.guest_talk
1012 = GNUNET_SOCIAL_guest_talk (gst, "_converse_guest", tmit.env,
1013 &notify_data, &tmit,
1014 GNUNET_SOCIAL_TALK_NONE);
1015}
1016
1017
1018static void
1019host_announce ()
1020{
1021 test = TEST_HOST_ANNOUNCE;
1022
1023 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1024 "Test #%u: Host announcement.\n", test);
1025
1026 tmit = (struct TransmitClosure) {};
1027 tmit.env = GNUNET_PSYC_env_create ();
1028 GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN,
1029 "_foo", DATA2ARG ("bar baz"));
1030 GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN,
1031 "_foo_bar", DATA2ARG ("foo bar"));
1032 GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN,
1033 "_foo_bar_baz", DATA2ARG ("foo bar baz"));
1034 tmit.data[0] = "aaa bbb ccc ";
1035 tmit.data[1] = "abc def ghi jkl.\n";
1036 tmit.data_delay[1] = 1;
1037 tmit.data[2] = "testing one two three ";
1038 tmit.data[3] = "four five.\n";
1039 tmit.data_count = 4;
1040
1041 tmit.host_ann
1042 = GNUNET_SOCIAL_host_announce (hst, "_converse_host", tmit.env,
1043 &notify_data, &tmit,
1044 GNUNET_SOCIAL_ANNOUNCE_NONE);
1045}
1046
1047
1048static void
1049host_announce2 ()
1050{
1051 GNUNET_assert (2 == mod_foo_bar_rcls.n);
1052 GNUNET_PSYC_slicer_modifier_remove (guest_slicer, "_foo_bar",
1053 guest_recv_mod_foo_bar);
1054
1055 test = TEST_HOST_ANNOUNCE2;
1056
1057 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1058 "Test #%u: Host announcement 2.\n", test);
1059
1060 tmit = (struct TransmitClosure) {};
1061 tmit.env = GNUNET_PSYC_env_create ();
1062 GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN,
1063 "_foo2", DATA2ARG ("BAR BAZ"));
1064 GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN,
1065 "_foo2_bar", DATA2ARG ("FOO BAR"));
1066 GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN,
1067 "_foo2_bar_baz", DATA2ARG ("FOO BAR BAZ"));
1068 tmit.data[0] = "AAA BBB CCC ";
1069 tmit.data[1] = "ABC DEF GHI JKL.\n";
1070 tmit.data[2] = "TESTING ONE TWO THREE.\n";
1071 tmit.data_count = 3;
1072
1073 tmit.host_ann
1074 = GNUNET_SOCIAL_host_announce (hst, "_converse_host_two", tmit.env,
1075 &notify_data, &tmit,
1076 GNUNET_SOCIAL_ANNOUNCE_NONE);
1077}
1078
1079
1080static void
1081guest_recv_entry_decision (void *cls,
1082 int is_admitted,
1083 const struct GNUNET_PSYC_Message *entry_msg)
1084{
1085 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1086 "Test #%u: Guest received entry decision (try %u): %d.\n",
1087 test, join_req_count, is_admitted);
1088
1089 if (NULL != entry_msg)
1090 {
1091 struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
1092 const char *method_name = NULL;
1093 const void *data = NULL;
1094 uint16_t data_size = 0;
1095 struct GNUNET_PSYC_MessageHeader *
1096 pmsg = GNUNET_PSYC_message_header_create_from_psyc (entry_msg);
1097 GNUNET_PSYC_message_parse (pmsg, &method_name, env, &data, &data_size);
1098 GNUNET_free (pmsg);
1099
1100 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1101 "%s\n%.*s\n",
1102 method_name, data_size, (const char *) data);
1103 /** @todo FIXME: check response message */
1104 }
1105
1106 switch (test)
1107 {
1108 case TEST_GUEST_RECV_ENTRY_DCSN_REFUSE:
1109 GNUNET_assert (GNUNET_NO == is_admitted);
1110 test = TEST_HOST_ANSWER_DOOR_ADMIT;
1111 GNUNET_SOCIAL_guest_disconnect (gst, &guest_enter, NULL);
1112 break;
1113
1114 case TEST_GUEST_RECV_ENTRY_DCSN_ADMIT:
1115 GNUNET_assert (GNUNET_YES == is_admitted);
1116 host_announce ();
1117 break;
1118
1119 case TEST_GUEST_ENTER_BY_NAME:
1120 GNUNET_SCHEDULER_add_now (&schedule_reconnect, NULL);
1121 break;
1122
1123 default:
1124 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "invalid test: %d\n", test);
1125 GNUNET_assert (0);
1126 }
1127}
1128
1129
1130static void
1131host_answer_door (void *cls,
1132 struct GNUNET_SOCIAL_Nym *nym,
1133 const char *method_name,
1134 struct GNUNET_PSYC_Environment *env,
1135 const void *data,
1136 size_t data_size)
1137{
1138 join_req_count++;
1139
1140 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1141 "Test #%u: Host received entry request from guest (try %u).\n",
1142 (uint8_t) test, join_req_count);
1143 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1144 "%s\n%.*s\n",
1145 method_name, (int) data_size, (const char *) data);
1146
1147 switch (test)
1148 {
1149 case TEST_HOST_ANSWER_DOOR_REFUSE:
1150 test = TEST_GUEST_RECV_ENTRY_DCSN_REFUSE;
1151 join_resp = GNUNET_PSYC_message_create ("_notice_place_refuse", env,
1152 DATA2ARG ("Go away!"));
1153 GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_NO, join_resp);
1154 break;
1155
1156 case TEST_HOST_ANSWER_DOOR_ADMIT:
1157 test = TEST_GUEST_RECV_ENTRY_DCSN_ADMIT;
1158 // fall through
1159
1160 case TEST_GUEST_ENTER_BY_NAME:
1161 join_resp = GNUNET_PSYC_message_create ("_notice_place_admit", env,
1162 DATA2ARG ("Welcome, nym!"));
1163 GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_YES, join_resp);
1164 break;
1165
1166 default:
1167 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid test: #%u\n", test);
1168 GNUNET_assert (0);
1169 }
1170}
1171
1172
1173static void
1174guest_recv_local_enter (void *cls, int result,
1175 const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key,
1176 uint64_t max_message_id)
1177{
1178 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1179 "Test #%u: Guest entered local place: %d\n",
1180 test, result);
1181 GNUNET_assert (GNUNET_OK == result);
1182}
1183
1184
1185static void
1186guest_enter ()
1187{
1188 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1189 "Test #%u: Entering place as guest.\n", test);
1190
1191 struct GuestEnterMessage *emsg = &guest_enter_msg;
1192
1193 emsg->method_name = "_request_enter";
1194 emsg->env = GNUNET_PSYC_env_create ();
1195 GNUNET_PSYC_env_add (emsg->env, GNUNET_PSYC_OP_ASSIGN,
1196 "_abc", "abc def", 7);
1197 GNUNET_PSYC_env_add (emsg->env, GNUNET_PSYC_OP_ASSIGN,
1198 "_abc_def", "abc def ghi", 11);
1199 emsg->data = "let me in";
1200 emsg->data_size = strlen (emsg->data) + 1;
1201 emsg->msg = GNUNET_PSYC_message_create (emsg->method_name, emsg->env,
1202 emsg->data, emsg->data_size);
1203
1204 gst = GNUNET_SOCIAL_guest_enter (app, guest_ego, &place_pub_key,
1205 GNUNET_PSYC_SLAVE_JOIN_NONE,
1206 &this_peer, 0, NULL, emsg->msg, guest_slicer,
1207 guest_recv_local_enter,
1208 guest_recv_entry_decision, NULL);
1209 gst_plc = GNUNET_SOCIAL_guest_get_place (gst);
1210
1211 GNUNET_SOCIAL_place_msg_proc_set (gst_plc, "_converse",
1212 GNUNET_SOCIAL_MSG_PROC_SAVE);
1213}
1214
1215
1216static void
1217guest_enter_by_name ()
1218{
1219 test = TEST_GUEST_ENTER_BY_NAME;
1220 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1221 "Test #%u: Entering place by name as guest.\n", test);
1222
1223 struct GuestEnterMessage *emsg = &guest_enter_msg;
1224
1225 emsg->method_name = "_request_enter";
1226 emsg->env = GNUNET_PSYC_env_create ();
1227 GNUNET_PSYC_env_add (emsg->env, GNUNET_PSYC_OP_ASSIGN,
1228 "_abc", "abc def", 7);
1229 GNUNET_PSYC_env_add (emsg->env, GNUNET_PSYC_OP_ASSIGN,
1230 "_abc_def", "abc def ghi", 11);
1231 emsg->data = "let me in";
1232 emsg->data_size = strlen (emsg->data) + 1;
1233 emsg->msg = GNUNET_PSYC_message_create (emsg->method_name, emsg->env,
1234 emsg->data, emsg->data_size);
1235
1236 gst = GNUNET_SOCIAL_guest_enter_by_name (app, guest_ego,
1237 "home.host.gnu", "let.me*in!",
1238 emsg->msg, guest_slicer,
1239 guest_recv_local_enter,
1240 guest_recv_entry_decision, NULL);
1241 gst_plc = GNUNET_SOCIAL_guest_get_place (gst);
1242}
1243
1244
1245static void
1246app_recv_zone_add_nym_result (void *cls, int64_t result,
1247 const void *data, uint16_t data_size)
1248{
1249 GNUNET_assert (GNUNET_YES == result);
1250 is_guest_nym_added = GNUNET_YES;
1251}
1252
1253
1254static void
1255guest_init ()
1256{
1257 guest_pub_key = GNUNET_SOCIAL_ego_get_pub_key (guest_ego);
1258
1259 guest_slicer = GNUNET_PSYC_slicer_create ();
1260 GNUNET_PSYC_slicer_method_add (guest_slicer, "", NULL,
1261 guest_recv_method, guest_recv_modifier,
1262 guest_recv_data, guest_recv_eom, NULL);
1263 GNUNET_PSYC_slicer_modifier_add (guest_slicer, "_foo_bar",
1264 guest_recv_mod_foo_bar, &mod_foo_bar_rcls);
1265 test = TEST_HOST_ANSWER_DOOR_REFUSE;
1266
1267 GNUNET_SOCIAL_zone_add_nym (app, guest_ego, "host", host_pub_key,
1268 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES),
1269 app_recv_zone_add_nym_result, NULL);
1270}
1271
1272
1273static void
1274id_host_created (void *cls, const char *emsg)
1275{
1276 if (NULL != emsg)
1277 {
1278 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1279 "Test #%u: Could not create host identity: %s\n",
1280 test, emsg);
1281#if ! DEBUG_TEST_SOCIAL
1282 GNUNET_assert (0);
1283#endif
1284 }
1285
1286}
1287
1288
1289static void
1290id_guest_created (void *cls, const char *emsg)
1291{
1292 if (NULL != emsg)
1293 {
1294 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1295 "Test #%u: Could not create guest identity: %s\n",
1296 test, emsg);
1297#if ! DEBUG_TEST_SOCIAL
1298 GNUNET_assert (0);
1299#endif
1300 }
1301 //if (NULL != guest_ego)
1302 // guest_init ();
1303}
1304
1305
1306static void
1307host_entered (void *cls, int result,
1308 const struct GNUNET_CRYPTO_EddsaPublicKey *home_pub_key,
1309 uint64_t max_message_id)
1310{
1311 place_pub_key = *home_pub_key;
1312 GNUNET_CRYPTO_hash (&place_pub_key, sizeof (place_pub_key), &place_pub_hash);
1313 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1314 "Test #%u: Host entered place %s\n",
1315 test, GNUNET_h2s (&place_pub_hash));
1316 guest_enter ();
1317}
1318
1319
1320static void
1321host_enter ()
1322{
1323 host_slicer = GNUNET_PSYC_slicer_create ();
1324 GNUNET_PSYC_slicer_method_add (host_slicer, "", NULL,
1325 host_recv_method, host_recv_modifier,
1326 host_recv_data, host_recv_eom, NULL);
1327
1328 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1329 "Test #%u: Entering place as host.\n", test);
1330 test = TEST_HOST_ENTER;
1331 hst = GNUNET_SOCIAL_host_enter (app, host_ego,
1332 GNUNET_PSYC_CHANNEL_PRIVATE,
1333 host_slicer, host_entered,
1334 host_answer_door, host_farewell, NULL);
1335 hst_plc = GNUNET_SOCIAL_host_get_place (hst);
1336
1337 GNUNET_SOCIAL_place_msg_proc_set (hst_plc, "_converse",
1338 GNUNET_SOCIAL_MSG_PROC_RELAY);
1339}
1340
1341
1342static void
1343start_app_if_ready ()
1344{
1345 if (NULL == identity_host_ego || NULL == identity_guest_ego)
1346 {
1347 return;
1348 }
1349 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1350 "starting app...\n");
1351 app = GNUNET_SOCIAL_app_connect (cfg,
1352 app_id,
1353 app_recv_ego,
1354 app_recv_host,
1355 app_recv_guest,
1356 app_connected,
1357 NULL);
1358}
1359
1360
1361static void
1362identity_ego_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego,
1363 void **ctx, const char *name)
1364{
1365 if (NULL != ego)
1366 {
1367 if (ego == identity_host_ego)
1368 {
1369 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1370 "Host ego deleted\n");
1371 }
1372 else if (ego == identity_guest_ego)
1373 {
1374 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1375 "Guest ego deleted\n");
1376 }
1377 else if (0 == strcmp (name, host_name))
1378 {
1379 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1380 "Created ego %s\n",
1381 name);
1382 identity_host_ego = ego;
1383 start_app_if_ready ();
1384 }
1385 else if (0 == strcmp (name, guest_name))
1386 {
1387 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1388 "Created guest ego %s\n",
1389 name);
1390 identity_guest_ego = ego;
1391 start_app_if_ready ();
1392 }
1393 }
1394}
1395
1396
1397/**
1398 * Main function of the test, run from scheduler.
1399 *
1400 * @param cls NULL
1401 * @param cfg configuration we use (also to connect to Social service)
1402 * @param peer handle to access more of the peer (not used)
1403 */
1404static void
1405#if DEBUG_TEST_SOCIAL
1406run (void *cls, char *const *args, const char *cfgfile,
1407 const struct GNUNET_CONFIGURATION_Handle *c)
1408#else
1409run (void *cls,
1410 const struct GNUNET_CONFIGURATION_Handle *c,
1411 struct GNUNET_TESTING_Peer *peer)
1412#endif
1413{
1414 cfg = c;
1415 res = 1;
1416 end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
1417 &end_badly, NULL);
1418 GNUNET_SCHEDULER_add_shutdown (&end_shutdown,
1419 NULL);
1420 GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer);
1421
1422 id = GNUNET_IDENTITY_connect (cfg, &identity_ego_cb, NULL);
1423
1424 test = TEST_IDENTITIES_CREATE;
1425 GNUNET_IDENTITY_create (id, host_name, &id_host_created, NULL);
1426 GNUNET_IDENTITY_create (id, guest_name, &id_guest_created, NULL);
1427}
1428
1429
1430int
1431main (int argc, char *argv[])
1432{
1433 res = 1;
1434#if DEBUG_TEST_SOCIAL
1435 const struct GNUNET_GETOPT_CommandLineOption opts[] = {
1436 GNUNET_GETOPT_OPTION_END
1437 };
1438 if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-social",
1439 "test-social [options]",
1440 opts, &run, NULL))
1441 return 1;
1442#else
1443 if (0 != GNUNET_TESTING_peer_run ("test-social", "test_social.conf", &run, NULL))
1444 return 1;
1445#endif
1446 return res;
1447}
1448
1449/* 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 @@
1@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/gnunet-test-social/
5
6[social]
7IMMEDIATE_START = YES
8
9[transport]
10PLUGINS = tcp
11
12[nat]
13DISABLEV6 = YES
14ENABLE_UPNP = NO
15BEHIND_NAT = NO
16ALLOW_NAT = NO
17INTERNAL_ADDRESS = 127.0.0.1
18EXTERNAL_ADDRESS = 127.0.0.1
19