aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2019-02-23 10:48:08 +0100
committerChristian Grothoff <christian@grothoff.org>2019-02-23 10:48:08 +0100
commitf1e8076ed474a429aff32839ed5f8fc20371839c (patch)
treebb38cb99b0e9cb7b937d33b539e74b9eb9fe4d32 /src
parent3d0f1dd3805bfef30ff7a7f8e246a926b7fa7838 (diff)
parent7b01b7b1760cc973719c9a20123f99e4a7e1b5a6 (diff)
downloadgnunet-f1e8076ed474a429aff32839ed5f8fc20371839c.tar.gz
gnunet-f1e8076ed474a429aff32839ed5f8fc20371839c.zip
merge
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am8
-rw-r--r--src/arm/arm.conf.in2
-rw-r--r--src/ats-tests/Makefile.am1
-rw-r--r--src/ats/Makefile.am4
-rw-r--r--src/cadet/cadet.h10
-rw-r--r--src/cadet/cadet_api_get_path.c13
-rw-r--r--src/cadet/cadet_test_lib.c4
-rw-r--r--src/cadet/gnunet-cadet.c16
-rw-r--r--src/cadet/gnunet-service-cadet.c10
-rw-r--r--src/consensus/consensus-simulation.py.in18
-rw-r--r--src/consensus/test_consensus.conf4
-rw-r--r--src/datacache/perf_datacache.c4
-rw-r--r--src/datacache/test_datacache.c4
-rw-r--r--src/datacache/test_datacache_quota.c4
-rw-r--r--src/datastore/perf_datastore_api.c4
-rw-r--r--src/datastore/perf_plugin_datastore.c6
-rw-r--r--src/datastore/plugin_datastore_postgres.c8
-rw-r--r--src/datastore/test_datastore_api.c10
-rw-r--r--src/datastore/test_datastore_api_management.c6
-rw-r--r--src/datastore/test_plugin_datastore.c6
-rw-r--r--src/dht/test_dht_tools.py.in2
-rw-r--r--src/dv/.gitignore2
-rw-r--r--src/dv/Makefile.am100
-rw-r--r--src/dv/dv.conf.in15
-rw-r--r--src/dv/dv.h172
-rw-r--r--src/dv/dv_api.c467
-rw-r--r--src/dv/gnunet-dv.c185
-rw-r--r--src/dv/gnunet-service-dv.c2146
-rw-r--r--src/dv/plugin_transport_dv.c910
-rw-r--r--src/dv/template_dv.conf33
-rw-r--r--src/dv/test_transport_blacklist.c69
-rw-r--r--src/dv/test_transport_blacklist_data.conf5
-rw-r--r--src/dv/test_transport_dv.c131
-rw-r--r--src/dv/test_transport_dv_data.conf19
-rw-r--r--src/fs/Makefile.am5
-rw-r--r--src/fs/fs.conf.in2
-rw-r--r--src/fs/fs_dirmetascan.c8
-rw-r--r--src/fs/fs_publish.c18
-rw-r--r--src/fs/gnunet-publish.c4
-rw-r--r--src/fs/gnunet-search.c5
-rw-r--r--src/fs/gnunet-service-fs_cadet_client.c21
-rwxr-xr-xsrc/fs/test_gnunet_fs_psd.py.in1
-rw-r--r--src/gns/.gitignore6
-rw-r--r--src/gns/Makefile.am18
-rw-r--r--src/gns/gnunet-gns-proxy-setup-ca.in (renamed from src/gns/gnunet-gns-proxy-setup-ca)9
-rw-r--r--src/gns/gnunet-gns-proxy.c7
-rw-r--r--src/gns/openssl.cnf245
-rw-r--r--src/gns/test_gns_nick_shorten.conf24
-rwxr-xr-xsrc/gns/test_gns_rel_expiration.sh7
-rw-r--r--src/include/Makefile.am17
-rw-r--r--src/include/gnunet_cadet_service.h21
-rw-r--r--src/include/gnunet_common.h3
-rw-r--r--src/include/gnunet_dv_service.h166
-rw-r--r--src/include/gnunet_hello_lib.h2
-rw-r--r--src/include/gnunet_multicast_service.h925
-rw-r--r--src/include/gnunet_namestore_plugin.h9
-rw-r--r--src/include/gnunet_protocols.h35
-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_rps_service.h2
-rw-r--r--src/include/gnunet_sensor_service.h199
-rw-r--r--src/include/gnunet_sensor_util_lib.h520
-rw-r--r--src/include/gnunet_sensordashboard_service.h55
-rw-r--r--src/include/gnunet_social_service.h1344
-rw-r--r--src/include/gnunet_transport_address_service.h116
-rw-r--r--src/include/gnunet_transport_hello_service.h4
-rw-r--r--src/include/platform.h12
-rw-r--r--src/integration-tests/confs/c_bootstrap_server.conf21
-rw-r--r--src/integration-tests/confs/c_nat_client.conf7
-rw-r--r--src/integration-tests/confs/c_no_nat_client.conf11
-rw-r--r--src/integration-tests/confs/c_no_nat_client_2.conf10
-rw-r--r--src/integration-tests/gnunet_pyexpect.py.in1
-rw-r--r--src/integration-tests/gnunet_testing.py.in104
-rwxr-xr-xsrc/integration-tests/test_integration_bootstrap_and_connect.py.in3
-rwxr-xr-xsrc/integration-tests/test_integration_clique.py.in1
-rwxr-xr-xsrc/integration-tests/test_integration_disconnect.py.in87
-rwxr-xr-xsrc/integration-tests/test_integration_disconnect_nat.py.in3
-rwxr-xr-xsrc/integration-tests/test_integration_reconnect.py.in113
-rwxr-xr-xsrc/integration-tests/test_integration_reconnect_nat.py.in3
-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/namecache/plugin_namecache_flat.c2
-rw-r--r--src/namecache/test_plugin_namecache.c4
-rw-r--r--src/namestore/gnunet-service-namestore.c45
-rw-r--r--src/namestore/plugin_namestore_heap.c93
-rw-r--r--src/namestore/plugin_namestore_postgres.c1
-rw-r--r--src/namestore/plugin_namestore_sqlite.c1
-rw-r--r--src/namestore/test_plugin_namestore.c7
-rw-r--r--src/peerinfo/peerinfo_api.c5
-rw-r--r--src/peerstore/Makefile.am4
-rw-r--r--src/peerstore/peerstore_api.c140
-rw-r--r--src/peerstore/plugin_peerstore_flat.c4
-rw-r--r--src/peerstore/test_plugin_peerstore.c4
-rw-r--r--src/pq/pq_result_helper.c2
-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/rest-plugins/Makefile.am2
-rw-r--r--src/rest-plugins/plugin_rest_openid_connect.c98
-rw-r--r--src/revocation/test_local_revocation.py.in1
-rw-r--r--src/rps/gnunet-rps-profiler.c16
-rw-r--r--src/rps/gnunet-service-rps.c173
-rw-r--r--src/rps/gnunet-service-rps_custommap.c39
-rw-r--r--src/rps/profiler_rps.conf3
-rw-r--r--src/rps/rps-test_util.c55
-rw-r--r--src/rps/rps-test_util.h4
-rw-r--r--src/rps/rps.h2
-rw-r--r--src/rps/rps_api.c2
-rw-r--r--src/rps/test_rps.c4
-rw-r--r--src/rps/test_rps.conf2
-rw-r--r--src/secretsharing/gnunet-service-secretsharing.c60
-rw-r--r--src/secretsharing/secretsharing.conf.in3
-rw-r--r--src/secretsharing/test_secretsharing.conf4
-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
-rw-r--r--src/sq/sq.c2
-rw-r--r--src/testbed/test_testbed_api_template.conf4
-rw-r--r--src/testing/Makefile.am3
-rw-r--r--src/testing/test_testing_defaults.conf4
-rw-r--r--src/testing/test_testing_sharedservices.conf4
-rw-r--r--src/testing/testing.c8
-rw-r--r--src/topology/friends.c2
-rw-r--r--src/topology/test_gnunet_daemon_topology_data.conf4
-rw-r--r--src/transport/Makefile.am13
-rw-r--r--src/transport/gnunet-communicator-tcp.c2
-rw-r--r--src/transport/gnunet-communicator-udp.c8
-rw-r--r--src/transport/gnunet-service-tng.c349
-rw-r--r--src/transport/gnunet-service-transport_validation.c5
-rw-r--r--src/transport/plugin_transport_tcp.c8
-rw-r--r--src/transport/transport.h26
-rw-r--r--src/transport/transport_api2_address.c249
-rw-r--r--src/transport/transport_api_core.c2
-rw-r--r--src/util/.gitignore1
-rw-r--r--src/util/Makefile.am9
-rw-r--r--src/util/container_multihashmap.c23
-rw-r--r--src/util/container_multihashmap32.c26
-rw-r--r--src/util/container_multipeermap.c34
-rw-r--r--src/util/container_multishortmap.c36
-rw-r--r--src/util/dnsparser.c13
-rwxr-xr-xsrc/util/gnunet-qr.py.in6
-rw-r--r--src/util/gnunet-service-resolver.c392
-rw-r--r--src/util/mq.c1
-rw-r--r--src/util/scheduler.c4
-rw-r--r--src/util/service.c2
196 files changed, 2060 insertions, 46524 deletions
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/arm/arm.conf.in b/src/arm/arm.conf.in
index 64ae35786..dc32f5498 100644
--- a/src/arm/arm.conf.in
+++ b/src/arm/arm.conf.in
@@ -16,7 +16,7 @@ UNIX_MATCH_GID = YES
16# logging with a new log file each day. Note that only the last 3 16# logging with a new log file each day. Note that only the last 3
17# log files are preserved. 17# log files are preserved.
18# GLOBAL_POSTFIX = -l $GNUNET_CACHE_HOME/{}-%Y-%m-%d.log 18# GLOBAL_POSTFIX = -l $GNUNET_CACHE_HOME/{}-%Y-%m-%d.log
19GLOBAL_PREFIX = @MONKEYPREFIX@ 19GLOBAL_PREFIX =
20 20
21# If set to YES, ARM will only start services that are marked as 21# If set to YES, ARM will only start services that are marked as
22# system-level services (and we'll expect a second ARM to be 22# system-level services (and we'll expect a second ARM to be
diff --git a/src/ats-tests/Makefile.am b/src/ats-tests/Makefile.am
index c85645b9d..83f9e1b6a 100644
--- a/src/ats-tests/Makefile.am
+++ b/src/ats-tests/Makefile.am
@@ -60,6 +60,7 @@ libgnunetatstesting_la_SOURCES = \
60libgnunetatstesting_la_LIBADD = \ 60libgnunetatstesting_la_LIBADD = \
61 $(top_builddir)/src/testbed/libgnunettestbed.la \ 61 $(top_builddir)/src/testbed/libgnunettestbed.la \
62 $(top_builddir)/src/core/libgnunetcore.la \ 62 $(top_builddir)/src/core/libgnunetcore.la \
63 $(top_builddir)/src/transport/libgnunettransport.la \
63 $(top_builddir)/src/ats/libgnunetats.la \ 64 $(top_builddir)/src/ats/libgnunetats.la \
64 $(top_builddir)/src/util/libgnunetutil.la \ 65 $(top_builddir)/src/util/libgnunetutil.la \
65 $(GN_LIBINTL) 66 $(GN_LIBINTL)
diff --git a/src/ats/Makefile.am b/src/ats/Makefile.am
index 2a62d71bd..ac8a411eb 100644
--- a/src/ats/Makefile.am
+++ b/src/ats/Makefile.am
@@ -97,6 +97,7 @@ libgnunet_plugin_ats_mlp_la_SOURCES = \
97libgnunet_plugin_ats_mlp_la_LIBADD = \ 97libgnunet_plugin_ats_mlp_la_LIBADD = \
98 libgnunetats.la \ 98 libgnunetats.la \
99 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 99 $(top_builddir)/src/statistics/libgnunetstatistics.la \
100 $(top_builddir)/src/nt/libgnunetnt.la \
100 $(top_builddir)/src/util/libgnunetutil.la 101 $(top_builddir)/src/util/libgnunetutil.la
101libgnunet_plugin_ats_mlp_la_LDFLAGS = \ 102libgnunet_plugin_ats_mlp_la_LDFLAGS = \
102 $(GN_PLUGIN_LDFLAGS) \ 103 $(GN_PLUGIN_LDFLAGS) \
@@ -107,6 +108,7 @@ libgnunet_plugin_ats_ril_la_SOURCES = \
107libgnunet_plugin_ats_ril_la_LIBADD = \ 108libgnunet_plugin_ats_ril_la_LIBADD = \
108 libgnunetats.la \ 109 libgnunetats.la \
109 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 110 $(top_builddir)/src/statistics/libgnunetstatistics.la \
111 $(top_builddir)/src/nt/libgnunetnt.la \
110 $(top_builddir)/src/util/libgnunetutil.la \ 112 $(top_builddir)/src/util/libgnunetutil.la \
111 $(LTLIBINTL) 113 $(LTLIBINTL)
112libgnunet_plugin_ats_ril_la_LDFLAGS = \ 114libgnunet_plugin_ats_ril_la_LDFLAGS = \
@@ -214,6 +216,8 @@ EXTRA_DIST = \
214 ats.h ats2.h \ 216 ats.h ats2.h \
215 plugin_ats2_common.c \ 217 plugin_ats2_common.c \
216 test_delay \ 218 test_delay \
219 test_ats2_lib.conf \
220 test_ats_api.conf \
217 test_ats_api_mlp.conf \ 221 test_ats_api_mlp.conf \
218 test_ats_api_ril.conf \ 222 test_ats_api_ril.conf \
219 test_ats_api_proportional.conf 223 test_ats_api_proportional.conf
diff --git a/src/cadet/cadet.h b/src/cadet/cadet.h
index 51296ae50..f6cc860cc 100644
--- a/src/cadet/cadet.h
+++ b/src/cadet/cadet.h
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -323,9 +323,9 @@ struct GNUNET_CADET_LocalInfoPath
323 struct GNUNET_MessageHeader header; 323 struct GNUNET_MessageHeader header;
324 324
325 /** 325 /**
326 * Zero. 326 * Offset of the peer that was requested.
327 */ 327 */
328 uint32_t reserved GNUNET_PACKED; 328 uint32_t off GNUNET_PACKED;
329}; 329};
330 330
331 331
@@ -338,7 +338,7 @@ struct GNUNET_CADET_LocalInfoPeers
338 * Type: #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS 338 * Type: #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS
339 */ 339 */
340 struct GNUNET_MessageHeader header; 340 struct GNUNET_MessageHeader header;
341 341
342 /** 342 /**
343 * Number of paths. 343 * Number of paths.
344 */ 344 */
@@ -348,7 +348,7 @@ struct GNUNET_CADET_LocalInfoPeers
348 * Do we have a tunnel toward this peer? 348 * Do we have a tunnel toward this peer?
349 */ 349 */
350 int16_t tunnel GNUNET_PACKED; 350 int16_t tunnel GNUNET_PACKED;
351 351
352 /** 352 /**
353 * Shortest known path. 353 * Shortest known path.
354 */ 354 */
diff --git a/src/cadet/cadet_api_get_path.c b/src/cadet/cadet_api_get_path.c
index 2f35e365e..fcc79c3d5 100644
--- a/src/cadet/cadet_api_get_path.c
+++ b/src/cadet/cadet_api_get_path.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -66,7 +66,7 @@ struct GNUNET_CADET_GetPath
66 * Backoff for reconnect attempts. 66 * Backoff for reconnect attempts.
67 */ 67 */
68 struct GNUNET_TIME_Relative backoff; 68 struct GNUNET_TIME_Relative backoff;
69 69
70 /** 70 /**
71 * Peer we want information about. 71 * Peer we want information about.
72 */ 72 */
@@ -109,7 +109,7 @@ check_get_path (void *cls,
109/** 109/**
110 * Process a local peer info reply, pass info to the user. 110 * Process a local peer info reply, pass info to the user.
111 * 111 *
112 * @param cls Closure 112 * @param cls Closure
113 * @param message Message itself. 113 * @param message Message itself.
114 */ 114 */
115static void 115static void
@@ -118,9 +118,10 @@ handle_get_path (void *cls,
118{ 118{
119 struct GNUNET_CADET_GetPath *gp = cls; 119 struct GNUNET_CADET_GetPath *gp = cls;
120 struct GNUNET_CADET_PeerPathDetail ppd; 120 struct GNUNET_CADET_PeerPathDetail ppd;
121 121
122 ppd.peer = gp->id; 122 ppd.peer = gp->id;
123 ppd.path = (const struct GNUNET_PeerIdentity *) &message[1]; 123 ppd.path = (const struct GNUNET_PeerIdentity *) &message[1];
124 ppd.target_offset = ntohl (message->off);
124 ppd.path_length = (ntohs (message->header.size) - sizeof (*message)) 125 ppd.path_length = (ntohs (message->header.size) - sizeof (*message))
125 / sizeof (struct GNUNET_PeerIdentity); 126 / sizeof (struct GNUNET_PeerIdentity);
126 gp->path_cb (gp->path_cb_cls, 127 gp->path_cb (gp->path_cb_cls,
@@ -131,7 +132,7 @@ handle_get_path (void *cls,
131/** 132/**
132 * Process a local peer info reply, pass info to the user. 133 * Process a local peer info reply, pass info to the user.
133 * 134 *
134 * @param cls Closure 135 * @param cls Closure
135 * @param message Message itself. 136 * @param message Message itself.
136 */ 137 */
137static void 138static void
@@ -177,7 +178,7 @@ error_handler (void *cls,
177 gp); 178 gp);
178} 179}
179 180
180 181
181/** 182/**
182 * Reconnect to the service and try again. 183 * Reconnect to the service and try again.
183 * 184 *
diff --git a/src/cadet/cadet_test_lib.c b/src/cadet/cadet_test_lib.c
index 7d83f496a..db16e4015 100644
--- a/src/cadet/cadet_test_lib.c
+++ b/src/cadet/cadet_test_lib.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -279,7 +279,7 @@ cadet_test_run (void *cls,
279 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 279 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
280 "Some links failed (%u), ending\n", 280 "Some links failed (%u), ending\n",
281 links_failed); 281 links_failed);
282 exit (2); 282 exit (77);
283 } 283 }
284 if (num_peers != ctx->num_peers) 284 if (num_peers != ctx->num_peers)
285 { 285 {
diff --git a/src/cadet/gnunet-cadet.c b/src/cadet/gnunet-cadet.c
index dba517a7b..932d069a1 100644
--- a/src/cadet/gnunet-cadet.c
+++ b/src/cadet/gnunet-cadet.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -103,7 +103,7 @@ static struct GNUNET_CADET_GetPath *gpo;
103 103
104/** 104/**
105 * Active peer listing operation. 105 * Active peer listing operation.
106 */ 106 */
107static struct GNUNET_CADET_PeersLister *plo; 107static struct GNUNET_CADET_PeersLister *plo;
108 108
109/** 109/**
@@ -220,7 +220,7 @@ shutdown_task (void *cls)
220 { 220 {
221 GNUNET_CADET_channel_destroy (ch); 221 GNUNET_CADET_channel_destroy (ch);
222 ch = NULL; 222 ch = NULL;
223 } 223 }
224 if (NULL != gpo) 224 if (NULL != gpo)
225 { 225 {
226 GNUNET_CADET_get_path_cancel (gpo); 226 GNUNET_CADET_get_path_cancel (gpo);
@@ -306,12 +306,12 @@ read_stdio (void *cls)
306 if (GNUNET_NO == echo) 306 if (GNUNET_NO == echo)
307 { 307 {
308 // Use MQ's notification if too much data of stdin is pooring in too fast. 308 // Use MQ's notification if too much data of stdin is pooring in too fast.
309 if (STREAM_BUFFER_SIZE < sent_pkt) 309 if (STREAM_BUFFER_SIZE < sent_pkt)
310 { 310 {
311 GNUNET_MQ_notify_sent (env, mq_cb, cls); 311 GNUNET_MQ_notify_sent (env, mq_cb, cls);
312 sent_pkt = 0; 312 sent_pkt = 0;
313 } 313 }
314 else 314 else
315 { 315 {
316 listen_stdio (); 316 listen_stdio ();
317 } 317 }
@@ -563,7 +563,7 @@ path_callback (void *cls,
563 ppd->path_length); 563 ppd->path_length);
564 for (unsigned int i = 0; i < ppd->path_length; i++) 564 for (unsigned int i = 0; i < ppd->path_length; i++)
565 FPRINTF (stdout, 565 FPRINTF (stdout,
566 "%s ", 566 (i == ppd->target_offset) ? "*%s* " : "%s ",
567 GNUNET_i2s (&ppd->path[i])); 567 GNUNET_i2s (&ppd->path[i]));
568 FPRINTF (stdout, 568 FPRINTF (stdout,
569 "\n"); 569 "\n");
@@ -626,7 +626,7 @@ show_peer (void *cls)
626 GNUNET_CRYPTO_eddsa_public_key_from_string (peer_id, 626 GNUNET_CRYPTO_eddsa_public_key_from_string (peer_id,
627 strlen (peer_id), 627 strlen (peer_id),
628 &pid.public_key)) 628 &pid.public_key))
629 { 629 {
630 fprintf (stderr, 630 fprintf (stderr,
631 _("Invalid peer ID `%s'\n"), 631 _("Invalid peer ID `%s'\n"),
632 peer_id); 632 peer_id);
@@ -859,7 +859,7 @@ main (int argc,
859 GNUNET_GETOPT_option_flag ('e', 859 GNUNET_GETOPT_option_flag ('e',
860 "echo", 860 "echo",
861 gettext_noop ("Activate echo mode"), 861 gettext_noop ("Activate echo mode"),
862 &echo), 862 &echo),
863 GNUNET_GETOPT_option_string ('o', 863 GNUNET_GETOPT_option_string ('o',
864 "open-port", 864 "open-port",
865 "SHARED_SECRET", 865 "SHARED_SECRET",
diff --git a/src/cadet/gnunet-service-cadet.c b/src/cadet/gnunet-service-cadet.c
index d64242943..e29330f99 100644
--- a/src/cadet/gnunet-service-cadet.c
+++ b/src/cadet/gnunet-service-cadet.c
@@ -886,6 +886,13 @@ path_info_iterator (void *cls,
886 path_size = sizeof (struct GNUNET_PeerIdentity) * path_length; 886 path_size = sizeof (struct GNUNET_PeerIdentity) * path_length;
887 if (sizeof (*resp) + path_size > UINT16_MAX) 887 if (sizeof (*resp) + path_size > UINT16_MAX)
888 { 888 {
889 /* try just giving the relevant path */
890 path_length = GNUNET_MIN ((UINT16_MAX - sizeof (*resp)) / sizeof (struct GNUNET_PeerIdentity),
891 off);
892 path_size = sizeof (struct GNUNET_PeerIdentity) * path_length;
893 }
894 if (sizeof (*resp) + path_size > UINT16_MAX)
895 {
889 LOG (GNUNET_ERROR_TYPE_WARNING, 896 LOG (GNUNET_ERROR_TYPE_WARNING,
890 "Path of %u entries is too long for info message\n", 897 "Path of %u entries is too long for info message\n",
891 path_length); 898 path_length);
@@ -899,9 +906,10 @@ path_info_iterator (void *cls,
899 /* Don't copy first peer. First peer is always the local one. Last 906 /* Don't copy first peer. First peer is always the local one. Last
900 * peer is always the destination (leave as 0, EOL). 907 * peer is always the destination (leave as 0, EOL).
901 */ 908 */
902 for (unsigned int i = 0; i <= off; i++) 909 for (unsigned int i = 0; i < path_length; i++)
903 id[i] = *GCP_get_id (GCPP_get_peer_at_offset (path, 910 id[i] = *GCP_get_id (GCPP_get_peer_at_offset (path,
904 i)); 911 i));
912 resp->off = htonl (off);
905 GNUNET_MQ_send (mq, 913 GNUNET_MQ_send (mq,
906 env); 914 env);
907 return GNUNET_YES; 915 return GNUNET_YES;
diff --git a/src/consensus/consensus-simulation.py.in b/src/consensus/consensus-simulation.py.in
index 38e29230a..161015d00 100644
--- a/src/consensus/consensus-simulation.py.in
+++ b/src/consensus/consensus-simulation.py.in
@@ -19,6 +19,10 @@
19 19
20from __future__ import absolute_import 20from __future__ import absolute_import
21from __future__ import print_function 21from __future__ import print_function
22from __future__ import division
23from builtins import str
24from builtins import range
25from past.utils import old_div
22import argparse 26import argparse
23import random 27import random
24from math import ceil, log, floor 28from math import ceil, log, floor
@@ -39,18 +43,18 @@ def bsc(n):
39 43
40def simulate(k, n, verbose): 44def simulate(k, n, verbose):
41 assert k < n 45 assert k < n
42 largest_arc = int(2**ceil(log(n, 2))) / 2 46 largest_arc = old_div(int(2**ceil(log(n, 2))), 2)
43 num_ghosts = (2 * largest_arc) - n 47 num_ghosts = (2 * largest_arc) - n
44 if verbose: 48 if verbose:
45 print("we have", num_ghosts, "ghost peers") 49 print("we have", num_ghosts, "ghost peers")
46 # n.b. all peers with idx<k are evil 50 # n.b. all peers with idx<k are evil
47 peers = range(n) 51 peers = list(range(n))
48 # py2-3 compatible, backwards. 52 # py2-3 compatible, backwards.
49 # refer to http://python-future.org/compatible_idioms.html#xrange 53 # refer to http://python-future.org/compatible_idioms.html#xrange
50 info = [1 << x for x in xrange(n)] 54 info = [1 << x for x in range(n)]
51 55
52 def done_p(): 56 def done_p():
53 for x in xrange(k, n): 57 for x in range(k, n):
54 if bsc(info[x]) < n-k: 58 if bsc(info[x]) < n-k:
55 return False 59 return False
56 return True 60 return True
@@ -63,7 +67,7 @@ def simulate(k, n, verbose):
63 if verbose: 67 if verbose:
64 print("-- subround --") 68 print("-- subround --")
65 new_info = [x for x in info] 69 new_info = [x for x in info]
66 for peer_physical in xrange(n): 70 for peer_physical in range(n):
67 peer_logical = peers[peer_physical] 71 peer_logical = peers[peer_physical]
68 peer_type = None 72 peer_type = None
69 partner_logical = (peer_logical + arc) % n 73 partner_logical = (peer_logical + arc) % n
@@ -105,6 +109,6 @@ if __name__ == "__main__":
105 109
106 args = parser.parse_args() 110 args = parser.parse_args()
107 sum = 0.0 111 sum = 0.0
108 for n in xrange(0, args.r): 112 for n in range(0, args.r):
109 sum += simulate(args.k, args.n, args.verbose) 113 sum += simulate(args.k, args.n, args.verbose)
110 print(sum / args.r) 114 print(old_div(sum, args.r))
diff --git a/src/consensus/test_consensus.conf b/src/consensus/test_consensus.conf
index fa42c3c1a..4f17fa359 100644
--- a/src/consensus/test_consensus.conf
+++ b/src/consensus/test_consensus.conf
@@ -81,3 +81,7 @@ WAN_QUOTA_OUT = unlimited
81 81
82[core] 82[core]
83USE_EPHEMERAL_KEYS = NO 83USE_EPHEMERAL_KEYS = NO
84
85[rps]
86START_ON_DEMAND = NO
87IMMEDIATE_START = NO
diff --git a/src/datacache/perf_datacache.c b/src/datacache/perf_datacache.c
index f33e62bae..4381171c5 100644
--- a/src/datacache/perf_datacache.c
+++ b/src/datacache/perf_datacache.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -132,7 +132,7 @@ FAILURE:
132int 132int
133main (int argc, char *argv[]) 133main (int argc, char *argv[])
134{ 134{
135 char cfg_name[128]; 135 char cfg_name[PATH_MAX];
136 char *const xargv[] = { 136 char *const xargv[] = {
137 "perf-datacache", 137 "perf-datacache",
138 "-c", 138 "-c",
diff --git a/src/datacache/test_datacache.c b/src/datacache/test_datacache.c
index e647ae833..d62a31c27 100644
--- a/src/datacache/test_datacache.c
+++ b/src/datacache/test_datacache.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -155,7 +155,7 @@ FAILURE:
155int 155int
156main (int argc, char *argv[]) 156main (int argc, char *argv[])
157{ 157{
158 char cfg_name[128]; 158 char cfg_name[PATH_MAX];
159 char *const xargv[] = { 159 char *const xargv[] = {
160 "test-datacache", 160 "test-datacache",
161 "-c", 161 "-c",
diff --git a/src/datacache/test_datacache_quota.c b/src/datacache/test_datacache_quota.c
index 117d8be4e..7c4e56ea5 100644
--- a/src/datacache/test_datacache_quota.c
+++ b/src/datacache/test_datacache_quota.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -123,7 +123,7 @@ int
123main (int argc, 123main (int argc,
124 char *argv[]) 124 char *argv[])
125{ 125{
126 char cfg_name[128]; 126 char cfg_name[PATH_MAX];
127 char *const xargv[] = { 127 char *const xargv[] = {
128 "test-datacache-quota", 128 "test-datacache-quota",
129 "-c", 129 "-c",
diff --git a/src/datastore/perf_datastore_api.c b/src/datastore/perf_datastore_api.c
index 939e60e4d..2c261b155 100644
--- a/src/datastore/perf_datastore_api.c
+++ b/src/datastore/perf_datastore_api.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -595,7 +595,7 @@ int
595main (int argc, 595main (int argc,
596 char *argv[]) 596 char *argv[])
597{ 597{
598 char cfg_name[128]; 598 char cfg_name[PATH_MAX];
599 599
600 plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]); 600 plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
601 GNUNET_snprintf (cfg_name, 601 GNUNET_snprintf (cfg_name,
diff --git a/src/datastore/perf_plugin_datastore.c b/src/datastore/perf_plugin_datastore.c
index 9ba8fa1b0..f68d1f389 100644
--- a/src/datastore/perf_plugin_datastore.c
+++ b/src/datastore/perf_plugin_datastore.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -519,8 +519,8 @@ run (void *cls, char *const *args, const char *cfgfile,
519int 519int
520main (int argc, char *argv[]) 520main (int argc, char *argv[])
521{ 521{
522 char dir_name[128]; 522 char dir_name[PATH_MAX];
523 char cfg_name[128]; 523 char cfg_name[PATH_MAX];
524 char *const xargv[] = { 524 char *const xargv[] = {
525 "perf-plugin-datastore", 525 "perf-plugin-datastore",
526 "-c", 526 "-c",
diff --git a/src/datastore/plugin_datastore_postgres.c b/src/datastore/plugin_datastore_postgres.c
index 94db6e116..0a3018411 100644
--- a/src/datastore/plugin_datastore_postgres.c
+++ b/src/datastore/plugin_datastore_postgres.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -153,7 +153,11 @@ init_connection (struct Plugin *plugin)
153 "SELECT hash FROM gn090", 153 "SELECT hash FROM gn090",
154 0), 154 0),
155 GNUNET_PQ_make_prepare ("estimate_size", 155 GNUNET_PQ_make_prepare ("estimate_size",
156 "SELECT SUM(LENGTH(value))+256*COUNT(*) AS total FROM gn090", 156 "SELECT CASE WHEN NOT EXISTS"
157 " (SELECT 1 FROM gn090)"
158 " THEN 0"
159 " ELSE (SELECT SUM(LENGTH(value))+256*COUNT(*) FROM gn090)"
160 "END AS total",
157 0), 161 0),
158 GNUNET_PQ_PREPARED_STATEMENT_END 162 GNUNET_PQ_PREPARED_STATEMENT_END
159 }; 163 };
diff --git a/src/datastore/test_datastore_api.c b/src/datastore/test_datastore_api.c
index fa96ea9b7..daf6cccb3 100644
--- a/src/datastore/test_datastore_api.c
+++ b/src/datastore/test_datastore_api.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -635,7 +635,7 @@ duc_dummy (void *cls,
635 635
636 636
637/** 637/**
638 * check if plugin is actually working 638 * check if plugin is actually working
639 */ 639 */
640static int 640static int
641test_plugin (const char *cfg_name) 641test_plugin (const char *cfg_name)
@@ -644,7 +644,7 @@ test_plugin (const char *cfg_name)
644 struct GNUNET_CONFIGURATION_Handle *cfg; 644 struct GNUNET_CONFIGURATION_Handle *cfg;
645 struct GNUNET_DATASTORE_PluginFunctions *api; 645 struct GNUNET_DATASTORE_PluginFunctions *api;
646 struct GNUNET_DATASTORE_PluginEnvironment env; 646 struct GNUNET_DATASTORE_PluginEnvironment env;
647 647
648 cfg = GNUNET_CONFIGURATION_create (); 648 cfg = GNUNET_CONFIGURATION_create ();
649 if (GNUNET_OK != 649 if (GNUNET_OK !=
650 GNUNET_CONFIGURATION_load (cfg, 650 GNUNET_CONFIGURATION_load (cfg,
@@ -691,9 +691,9 @@ int
691main (int argc, 691main (int argc,
692 char *argv[]) 692 char *argv[])
693{ 693{
694 char cfg_name[128]; 694 char cfg_name[PATH_MAX];
695 int ret; 695 int ret;
696 696
697 plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]); 697 plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
698 GNUNET_snprintf (cfg_name, 698 GNUNET_snprintf (cfg_name,
699 sizeof (cfg_name), 699 sizeof (cfg_name),
diff --git a/src/datastore/test_datastore_api_management.c b/src/datastore/test_datastore_api_management.c
index d592ccc80..d91fe748b 100644
--- a/src/datastore/test_datastore_api_management.c
+++ b/src/datastore/test_datastore_api_management.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -337,7 +337,7 @@ ignore_payload_cb (void *cls,
337static int 337static int
338test_plugin (const char *cfg_name) 338test_plugin (const char *cfg_name)
339{ 339{
340 char libname[128]; 340 char libname[PATH_MAX];
341 struct GNUNET_CONFIGURATION_Handle *cfg; 341 struct GNUNET_CONFIGURATION_Handle *cfg;
342 struct GNUNET_DATASTORE_PluginFunctions *api; 342 struct GNUNET_DATASTORE_PluginFunctions *api;
343 struct GNUNET_DATASTORE_PluginEnvironment env; 343 struct GNUNET_DATASTORE_PluginEnvironment env;
@@ -378,7 +378,7 @@ test_plugin (const char *cfg_name)
378int 378int
379main (int argc, char *argv[]) 379main (int argc, char *argv[])
380{ 380{
381 char cfg_name[128]; 381 char cfg_name[PATH_MAX];
382 int ret; 382 int ret;
383 383
384 plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]); 384 plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
diff --git a/src/datastore/test_plugin_datastore.c b/src/datastore/test_plugin_datastore.c
index 4b054314c..c37b8ddb9 100644
--- a/src/datastore/test_plugin_datastore.c
+++ b/src/datastore/test_plugin_datastore.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -436,8 +436,8 @@ run (void *cls, char *const *args, const char *cfgfile,
436int 436int
437main (int argc, char *argv[]) 437main (int argc, char *argv[])
438{ 438{
439 char dir_name[128]; 439 char dir_name[PATH_MAX];
440 char cfg_name[128]; 440 char cfg_name[PATH_MAX];
441 char *const xargv[] = { 441 char *const xargv[] = {
442 "test-plugin-datastore", 442 "test-plugin-datastore",
443 "-c", 443 "-c",
diff --git a/src/dht/test_dht_tools.py.in b/src/dht/test_dht_tools.py.in
index 05582cbd0..38a9f9622 100644
--- a/src/dht/test_dht_tools.py.in
+++ b/src/dht/test_dht_tools.py.in
@@ -124,7 +124,7 @@ time.sleep(1)
124 124
125print("TEST: Testing get...", end='') 125print("TEST: Testing get...", end='')
126rc, stdo, stde = r_get(['-k', 'testkey', '-T', '50 ms', '-t', '8'], want_stdo=True, failer=end_arm_failer) 126rc, stdo, stde = r_get(['-k', 'testkey', '-T', '50 ms', '-t', '8'], want_stdo=True, failer=end_arm_failer)
127stdo = stdo.replace('\r', '').splitlines() 127stdo = stdo.decode('utf-8').replace('\r', '').splitlines()
128expect = "Result 0, type 8:\ntestdata".splitlines() 128expect = "Result 0, type 8:\ntestdata".splitlines()
129if len(stdo) != 2 or len(expect) != 2 or stdo[0] != expect[0] or stdo[1] != expect[1]: 129if len(stdo) != 2 or len(expect) != 2 or stdo[0] != expect[0] or stdo[1] != expect[1]:
130 fail("output `{}' differs from expected `{}'".format(stdo, expect)) 130 fail("output `{}' differs from expected `{}'".format(stdo, expect))
diff --git a/src/dv/.gitignore b/src/dv/.gitignore
deleted file mode 100644
index b3068b1c4..000000000
--- a/src/dv/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
1gnunet-service-dv
2gnunet-dv
diff --git a/src/dv/Makefile.am b/src/dv/Makefile.am
deleted file mode 100644
index c44321151..000000000
--- a/src/dv/Makefile.am
+++ /dev/null
@@ -1,100 +0,0 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4if MINGW
5 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
6endif
7
8if USE_COVERAGE
9 AM_CFLAGS = --coverage -O0
10 XLIB = -lgcov
11endif
12
13plugindir = $(libdir)/gnunet
14
15libexecdir= $(pkglibdir)/libexec/
16
17pkgcfgdir= $(pkgdatadir)/config.d/
18
19pkgcfg_DATA = \
20 dv.conf
21
22lib_LTLIBRARIES = libgnunetdv.la
23
24plugin_LTLIBRARIES = libgnunet_plugin_transport_dv.la
25
26libgnunetdv_la_SOURCES = \
27 dv_api.c dv.h
28libgnunetdv_la_LIBADD = \
29 $(top_builddir)/src/util/libgnunetutil.la \
30 $(GN_LIBINTL) $(XLIB)
31libgnunetdv_la_LDFLAGS = \
32 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
33 -version-info 0:0:0
34
35
36noinst_PROGRAMS = \
37 gnunet-dv
38
39libexec_PROGRAMS = \
40 gnunet-service-dv
41
42gnunet_service_dv_SOURCES = \
43 gnunet-service-dv.c dv.h
44gnunet_service_dv_LDADD = \
45 $(top_builddir)/src/ats/libgnunetats.la \
46 $(top_builddir)/src/set/libgnunetset.la \
47 $(top_builddir)/src/statistics/libgnunetstatistics.la \
48 $(top_builddir)/src/core/libgnunetcore.la \
49 $(top_builddir)/src/util/libgnunetutil.la \
50 $(GN_LIBINTL)
51
52gnunet_dv_SOURCES = \
53 gnunet-dv.c dv.h
54gnunet_dv_LDADD = \
55 libgnunetdv.la \
56 $(top_builddir)/src/util/libgnunetutil.la \
57 $(GN_LIBINTL)
58
59libgnunet_plugin_transport_dv_la_SOURCES = \
60 plugin_transport_dv.c
61libgnunet_plugin_transport_dv_la_LIBADD = \
62 libgnunetdv.la \
63 $(top_builddir)/src/ats/libgnunetats.la \
64 $(top_builddir)/src/hello/libgnunethello.la \
65 $(top_builddir)/src/util/libgnunetutil.la
66libgnunet_plugin_transport_dv_la_LDFLAGS = \
67 $(GN_PLUGIN_LDFLAGS)
68
69if HAVE_TESTING
70check_PROGRAMS = \
71 test_transport_blacklist \
72 test_transport_dv
73endif
74
75if ENABLE_TEST_RUN
76 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
77 TESTS = $(check_PROGRAMS)
78endif
79
80test_transport_dv_SOURCES = \
81 test_transport_dv.c
82test_transport_dv_LDADD = \
83 $(top_builddir)/src/testbed/libgnunettestbed.la \
84 $(top_builddir)/src/core/libgnunetcore.la \
85 $(top_builddir)/src/transport/libgnunettransport.la \
86 $(top_builddir)/src/util/libgnunetutil.la
87
88test_transport_blacklist_SOURCES = \
89 test_transport_blacklist.c
90test_transport_blacklist_LDADD = \
91 $(top_builddir)/src/testbed/libgnunettestbed.la \
92 $(top_builddir)/src/core/libgnunetcore.la \
93 $(top_builddir)/src/transport/libgnunettransport.la \
94 $(top_builddir)/src/util/libgnunetutil.la
95
96EXTRA_DIST = \
97 test_transport_dv_data.conf \
98 test_transport_blacklist_data.conf \
99 template_dv.conf
100
diff --git a/src/dv/dv.conf.in b/src/dv/dv.conf.in
deleted file mode 100644
index 145c58be6..000000000
--- a/src/dv/dv.conf.in
+++ /dev/null
@@ -1,15 +0,0 @@
1[dv]
2START_ON_DEMAND = @START_ON_DEMAND@
3ACCEPT_FROM6 = ::1;
4ACCEPT_FROM = 127.0.0.1;
5BINARY = gnunet-service-dv
6HOSTNAME = localhost
7@UNIXONLY@ PORT = 2571
8UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-dv.sock
9UNIX_MATCH_UID = YES
10UNIX_MATCH_GID = YES
11# ACCEPT_FROM =
12# ACCEPT_FROM6 =
13# REJECT_FROM =
14# REJECT_FROM6 =
15# BINDTO =
diff --git a/src/dv/dv.h b/src/dv/dv.h
deleted file mode 100644
index b85d9c33f..000000000
--- a/src/dv/dv.h
+++ /dev/null
@@ -1,172 +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 Christian Grothoff
23 * @file dv/dv.h
24 * @brief IPC messages between DV service and DV plugin
25 */
26#ifndef DV_H
27#define DV_H
28
29#include "gnunet_common.h"
30
31GNUNET_NETWORK_STRUCT_BEGIN
32
33/**
34 * DV service tells plugin about a DV-connection being
35 * now available.
36 */
37struct GNUNET_DV_ConnectMessage
38{
39 /**
40 * Type: #GNUNET_MESSAGE_TYPE_DV_CONNECT
41 */
42 struct GNUNET_MessageHeader header;
43
44 /**
45 * The distance to the peer that we are now connected to
46 */
47 uint32_t distance GNUNET_PACKED;
48
49 /**
50 * The other peer (at the given distance).
51 */
52 struct GNUNET_PeerIdentity peer;
53
54 /**
55 * The network the peer is in
56 */
57 uint32_t network GNUNET_PACKED;
58
59};
60
61
62/**
63 * DV service tells plugin about a DV-connection being
64 * no longer available.
65 *
66 * Sender address is copied to the end of this struct,
67 * followed by the actual message received.
68 */
69struct GNUNET_DV_DisconnectMessage
70{
71 /**
72 * Type: #GNUNET_MESSAGE_TYPE_DV_DISCONNECT
73 */
74 struct GNUNET_MessageHeader header;
75
76 /**
77 * Always zero.
78 */
79 uint32_t reserved GNUNET_PACKED;
80
81 /**
82 * The peer that is no longer available.
83 */
84 struct GNUNET_PeerIdentity peer;
85
86};
87
88
89/**
90 * DV Message, contains a message that was received via DV for this
91 * peer. Send from the DV service to the DV plugin.
92 *
93 * Sender address is copied to the end of this struct,
94 * followed by the actual message received.
95 */
96struct GNUNET_DV_ReceivedMessage
97{
98 /**
99 * Type: #GNUNET_MESSAGE_TYPE_DV_RECV
100 */
101 struct GNUNET_MessageHeader header;
102
103 /**
104 * The distance to the peer that we received the message from
105 */
106 uint32_t distance GNUNET_PACKED;
107
108 /**
109 * The (actual) sender of the message
110 */
111 struct GNUNET_PeerIdentity sender;
112
113 /* payload follows */
114};
115
116
117/**
118 * Message from plugin to DV service, requesting a
119 * message to be routed.
120 */
121struct GNUNET_DV_SendMessage
122{
123 /**
124 * Type: #GNUNET_MESSAGE_TYPE_DV_SEND
125 */
126 struct GNUNET_MessageHeader header;
127
128 /**
129 * Reserved for alignment. 0.
130 */
131 uint32_t reserved GNUNET_PACKED;
132
133 /**
134 * The (actual) target of the message
135 */
136 struct GNUNET_PeerIdentity target;
137
138};
139
140
141/**
142 * Message from service to DV plugin, saying that our
143 * distance to another peer changed.
144 */
145struct GNUNET_DV_DistanceUpdateMessage
146{
147 /**
148 * Type: #GNUNET_MESSAGE_TYPE_DV_DISTANCE_CHANGED.
149 */
150 struct GNUNET_MessageHeader header;
151
152 /**
153 * What is the new distance?
154 */
155 uint32_t distance GNUNET_PACKED;
156
157 /**
158 * The peer for which the distance changed.
159 */
160 struct GNUNET_PeerIdentity peer;
161
162 /**
163 * The network the peer is in
164 */
165 uint32_t network GNUNET_PACKED;
166
167};
168
169
170GNUNET_NETWORK_STRUCT_END
171
172#endif
diff --git a/src/dv/dv_api.c b/src/dv/dv_api.c
deleted file mode 100644
index dd46ce9f5..000000000
--- a/src/dv/dv_api.c
+++ /dev/null
@@ -1,467 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009--2013, 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 dv/dv_api.c
23 * @brief library to access the DV service
24 * @author Christian Grothoff
25 * @author Nathan Evans
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_dv_service.h"
30#include "gnunet_protocols.h"
31#include "dv.h"
32#include "gnunet_transport_plugin.h"
33
34#define LOG(kind,...) GNUNET_log_from (kind, "dv-api",__VA_ARGS__)
35
36
37/**
38 * Information we track for each peer.
39 */
40struct ConnectedPeer
41{
42
43 /**
44 * Identity of the peer.
45 */
46 struct GNUNET_PeerIdentity pid;
47
48};
49
50
51/**
52 * Handle to the DV service.
53 */
54struct GNUNET_DV_ServiceHandle
55{
56
57 /**
58 * Connection to DV service.
59 */
60 struct GNUNET_MQ_Handle *mq;
61
62 /**
63 * Our configuration.
64 */
65 const struct GNUNET_CONFIGURATION_Handle *cfg;
66
67 /**
68 * Closure for the callbacks.
69 */
70 void *cls;
71
72 /**
73 * Function to call on connect events.
74 */
75 GNUNET_DV_ConnectCallback connect_cb;
76
77 /**
78 * Function to call on distance change events.
79 */
80 GNUNET_DV_DistanceChangedCallback distance_cb;
81
82 /**
83 * Function to call on disconnect events.
84 */
85 GNUNET_DV_DisconnectCallback disconnect_cb;
86
87 /**
88 * Function to call on receiving messages events.
89 */
90 GNUNET_DV_MessageReceivedCallback message_cb;
91
92 /**
93 * Information tracked per connected peer. Maps peer
94 * identities to `struct ConnectedPeer` entries.
95 */
96 struct GNUNET_CONTAINER_MultiPeerMap *peers;
97
98};
99
100
101/**
102 * Disconnect and then reconnect to the DV service.
103 *
104 * @param sh service handle
105 */
106static void
107reconnect (struct GNUNET_DV_ServiceHandle *sh);
108
109
110/**
111 * We got disconnected from the service and thus all of the
112 * connections need to be torn down.
113 *
114 * @param cls the `struct GNUNET_DV_ServiceHandle`
115 * @param key a peer identity
116 * @param value a `struct ConnectedPeer` to clean up
117 * @return #GNUNET_OK (continue to iterate)
118 */
119static int
120cleanup_send_cb (void *cls,
121 const struct GNUNET_PeerIdentity *key,
122 void *value)
123{
124 struct GNUNET_DV_ServiceHandle *sh = cls;
125 struct ConnectedPeer *peer = value;
126
127 GNUNET_assert (GNUNET_YES ==
128 GNUNET_CONTAINER_multipeermap_remove (sh->peers,
129 key,
130 peer));
131 sh->disconnect_cb (sh->cls,
132 key);
133 GNUNET_free (peer);
134 return GNUNET_OK;
135}
136
137
138/**
139 * Handles a message sent from the DV service to us.
140 * Parse it out and give it to the plugin.
141 *
142 * @param cls the handle to the DV API
143 * @param cm the message that was received
144 */
145static void
146handle_connect (void *cls,
147 const struct GNUNET_DV_ConnectMessage *cm)
148{
149 struct GNUNET_DV_ServiceHandle *sh = cls;
150 struct ConnectedPeer *peer;
151
152 peer = GNUNET_CONTAINER_multipeermap_get (sh->peers,
153 &cm->peer);
154 if (NULL != peer)
155 {
156 GNUNET_break (0);
157 reconnect (sh);
158 return;
159 }
160 peer = GNUNET_new (struct ConnectedPeer);
161 peer->pid = cm->peer;
162 GNUNET_assert (GNUNET_OK ==
163 GNUNET_CONTAINER_multipeermap_put (sh->peers,
164 &peer->pid,
165 peer,
166 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
167 sh->connect_cb (sh->cls,
168 &cm->peer,
169 ntohl (cm->distance),
170 (enum GNUNET_NetworkType) ntohl (cm->network));
171}
172
173
174/**
175 * Handles a message sent from the DV service to us.
176 * Parse it out and give it to the plugin.
177 *
178 * @param cls the handle to the DV API
179 * @param dm the message that was received
180 */
181static void
182handle_disconnect (void *cls,
183 const struct GNUNET_DV_DisconnectMessage *dm)
184{
185 struct GNUNET_DV_ServiceHandle *sh = cls;
186 struct ConnectedPeer *peer;
187
188 peer = GNUNET_CONTAINER_multipeermap_get (sh->peers,
189 &dm->peer);
190 if (NULL == peer)
191 {
192 GNUNET_break (0);
193 reconnect (sh);
194 return;
195 }
196 cleanup_send_cb (sh,
197 &dm->peer,
198 peer);
199}
200
201
202/**
203 * Handles a message sent from the DV service to us.
204 * Parse it out and give it to the plugin.
205 *
206 * @param cls the handle to the DV API
207 * @param msg the message that was received
208 */
209static void
210handle_distance_update (void *cls,
211 const struct GNUNET_DV_DistanceUpdateMessage *dum)
212{
213 struct GNUNET_DV_ServiceHandle *sh = cls;
214 struct ConnectedPeer *peer;
215
216 peer = GNUNET_CONTAINER_multipeermap_get (sh->peers,
217 &dum->peer);
218 if (NULL == peer)
219 {
220 GNUNET_break (0);
221 reconnect (sh);
222 return;
223 }
224 sh->distance_cb (sh->cls,
225 &dum->peer,
226 ntohl (dum->distance),
227 (enum GNUNET_NetworkType) ntohl (dum->network));
228}
229
230
231/**
232 * Handles a message sent from the DV service to us.
233 * Parse it out and give it to the plugin.
234 *
235 * @param cls the handle to the DV API
236 * @param rm the message that was received
237 */
238static int
239check_received (void *cls,
240 const struct GNUNET_DV_ReceivedMessage *rm)
241{
242 struct GNUNET_DV_ServiceHandle *sh = cls;
243 const struct GNUNET_MessageHeader *payload;
244
245 if (NULL ==
246 GNUNET_CONTAINER_multipeermap_get (sh->peers,
247 &rm->sender))
248 {
249 GNUNET_break (0);
250 return GNUNET_SYSERR;
251 }
252 if (ntohs (rm->header.size) - sizeof (struct GNUNET_DV_ReceivedMessage) <
253 sizeof (*payload))
254 {
255 GNUNET_break (0);
256 return GNUNET_SYSERR;
257 }
258 payload = (const struct GNUNET_MessageHeader *) &rm[1];
259 if (ntohs (rm->header.size) !=
260 sizeof (struct GNUNET_DV_ReceivedMessage) + ntohs (payload->size))
261 {
262 GNUNET_break (0);
263 return GNUNET_SYSERR;
264 }
265 return GNUNET_OK;
266}
267
268
269/**
270 * Handles a message sent from the DV service to us.
271 * Parse it out and give it to the plugin.
272 *
273 * @param cls the handle to the DV API
274 * @param rm the message that was received
275 */
276static void
277handle_received (void *cls,
278 const struct GNUNET_DV_ReceivedMessage *rm)
279{
280 struct GNUNET_DV_ServiceHandle *sh = cls;
281 const struct GNUNET_MessageHeader *payload;
282
283 payload = (const struct GNUNET_MessageHeader *) &rm[1];
284 sh->message_cb (sh->cls,
285 &rm->sender,
286 ntohl (rm->distance),
287 payload);
288}
289
290
291/**
292 * Generic error handler, called with the appropriate error code and
293 * the same closure specified at the creation of the message queue.
294 * Not every message queue implementation supports an error handler.
295 *
296 * @param cls closure with the `struct GNUNET_DV_ServiceHandle *`
297 * @param error error code
298 */
299static void
300mq_error_handler (void *cls,
301 enum GNUNET_MQ_Error error)
302{
303 struct GNUNET_DV_ServiceHandle *sh = cls;
304
305 reconnect (sh);
306}
307
308
309/**
310 * Disconnect and then reconnect to the DV service.
311 *
312 * @param sh service handle
313 */
314static void
315reconnect (struct GNUNET_DV_ServiceHandle *sh)
316{
317 struct GNUNET_MQ_MessageHandler handlers[] = {
318 GNUNET_MQ_hd_fixed_size (connect,
319 GNUNET_MESSAGE_TYPE_DV_CONNECT,
320 struct GNUNET_DV_ConnectMessage,
321 sh),
322 GNUNET_MQ_hd_fixed_size (disconnect,
323 GNUNET_MESSAGE_TYPE_DV_DISCONNECT,
324 struct GNUNET_DV_DisconnectMessage,
325 sh),
326 GNUNET_MQ_hd_fixed_size (distance_update,
327 GNUNET_MESSAGE_TYPE_DV_DISTANCE_CHANGED,
328 struct GNUNET_DV_DistanceUpdateMessage,
329 sh),
330 GNUNET_MQ_hd_var_size (received,
331 GNUNET_MESSAGE_TYPE_DV_RECV,
332 struct GNUNET_DV_ReceivedMessage,
333 sh),
334 GNUNET_MQ_handler_end ()
335 };
336 struct GNUNET_MessageHeader *sm;
337 struct GNUNET_MQ_Envelope *env;
338
339 if (NULL != sh->mq)
340 {
341 GNUNET_MQ_destroy (sh->mq);
342 sh->mq = NULL;
343 }
344 GNUNET_CONTAINER_multipeermap_iterate (sh->peers,
345 &cleanup_send_cb,
346 sh);
347 LOG (GNUNET_ERROR_TYPE_DEBUG,
348 "Connecting to DV service\n");
349 sh->mq = GNUNET_CLIENT_connect (sh->cfg,
350 "dv",
351 handlers,
352 &mq_error_handler,
353 sh);
354 if (NULL == sh->mq)
355 {
356 GNUNET_break (0);
357 return;
358 }
359 env = GNUNET_MQ_msg (sm,
360 GNUNET_MESSAGE_TYPE_DV_START);
361 GNUNET_MQ_send (sh->mq,
362 env);
363}
364
365
366/**
367 * Connect to the DV service.
368 *
369 * @param cfg configuration
370 * @param cls closure for callbacks
371 * @param connect_cb function to call on connects
372 * @param distance_cb function to call if distances change
373 * @param disconnect_cb function to call on disconnects
374 * @param message_cb function to call if we receive messages
375 * @return handle to access the service
376 */
377struct GNUNET_DV_ServiceHandle *
378GNUNET_DV_service_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
379 void *cls,
380 GNUNET_DV_ConnectCallback connect_cb,
381 GNUNET_DV_DistanceChangedCallback distance_cb,
382 GNUNET_DV_DisconnectCallback disconnect_cb,
383 GNUNET_DV_MessageReceivedCallback message_cb)
384{
385 struct GNUNET_DV_ServiceHandle *sh;
386
387 sh = GNUNET_new (struct GNUNET_DV_ServiceHandle);
388 sh->cfg = cfg;
389 sh->cls = cls;
390 sh->connect_cb = connect_cb;
391 sh->distance_cb = distance_cb;
392 sh->disconnect_cb = disconnect_cb;
393 sh->message_cb = message_cb;
394 sh->peers = GNUNET_CONTAINER_multipeermap_create (128,
395 GNUNET_YES);
396 reconnect (sh);
397 return sh;
398}
399
400
401/**
402 * Disconnect from DV service.
403 *
404 * @param sh service handle
405 */
406void
407GNUNET_DV_service_disconnect (struct GNUNET_DV_ServiceHandle *sh)
408{
409 if (NULL == sh)
410 return;
411 if (NULL != sh->mq)
412 {
413 GNUNET_MQ_destroy (sh->mq);
414 sh->mq = NULL;
415 }
416 GNUNET_CONTAINER_multipeermap_iterate (sh->peers,
417 &cleanup_send_cb,
418 sh);
419 GNUNET_CONTAINER_multipeermap_destroy (sh->peers);
420 GNUNET_free (sh);
421}
422
423
424/**
425 * Send a message via DV service.
426 *
427 * @param sh service handle
428 * @param target intended recpient
429 * @param msg message payload
430 */
431void
432GNUNET_DV_send (struct GNUNET_DV_ServiceHandle *sh,
433 const struct GNUNET_PeerIdentity *target,
434 const struct GNUNET_MessageHeader *msg)
435{
436 struct GNUNET_DV_SendMessage *sm;
437 struct ConnectedPeer *peer;
438 struct GNUNET_MQ_Envelope *env;
439
440 if (ntohs (msg->size) + sizeof (*sm) >= GNUNET_MAX_MESSAGE_SIZE)
441 {
442 GNUNET_break (0);
443 return;
444 }
445 LOG (GNUNET_ERROR_TYPE_DEBUG,
446 "Asked to send %u bytes of type %u to %s\n",
447 (unsigned int) ntohs (msg->size),
448 (unsigned int) ntohs (msg->type),
449 GNUNET_i2s (target));
450 peer = GNUNET_CONTAINER_multipeermap_get (sh->peers,
451 target);
452 if (NULL == peer)
453 {
454 GNUNET_break (0);
455 return;
456 }
457 GNUNET_assert (NULL != sh->mq);
458 env = GNUNET_MQ_msg_nested_mh (sm,
459 GNUNET_MESSAGE_TYPE_DV_SEND,
460 msg);
461 sm->target = *target;
462 GNUNET_MQ_send (sh->mq,
463 env);
464}
465
466
467/* end of dv_api.c */
diff --git a/src/dv/gnunet-dv.c b/src/dv/gnunet-dv.c
deleted file mode 100644
index 90d8144e5..000000000
--- a/src/dv/gnunet-dv.c
+++ /dev/null
@@ -1,185 +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 dv/gnunet-dv.c
22 * @brief DV monitoring command line tool
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_dv_service.h"
28
29/**
30 * Handle to DV service.
31 */
32static struct GNUNET_DV_ServiceHandle *sh;
33
34/**
35 * Was verbose specified?
36 */
37static unsigned int verbose;
38
39
40/**
41 * Function called if DV starts to be able to talk to a peer.
42 *
43 * @param cls closure
44 * @param peer newly connected peer
45 * @param distance distance to the peer
46 * @param network the network the next hop is located in
47 */
48static void
49connect_cb (void *cls,
50 const struct GNUNET_PeerIdentity *peer,
51 uint32_t distance,
52 enum GNUNET_NetworkType network)
53{
54 fprintf (stderr, "Connect: %s at %u\n",
55 GNUNET_i2s (peer),
56 (unsigned int) distance);
57}
58
59
60/**
61 * Function called if DV distance to a peer is changed.
62 *
63 * @param cls closure
64 * @param peer connected peer
65 * @param distance new distance to the peer
66 * @param network network used on first hop to peer
67 */
68static void
69change_cb (void *cls,
70 const struct GNUNET_PeerIdentity *peer,
71 uint32_t distance,
72 enum GNUNET_NetworkType network)
73{
74 fprintf (stderr, "Change: %s at %u\n",
75 GNUNET_i2s (peer),
76 (unsigned int) distance);
77}
78
79
80/**
81 * Function called if DV is no longer able to talk to a peer.
82 *
83 * @param cls closure
84 * @param peer peer that disconnected
85 */
86static void
87disconnect_cb (void *cls,
88 const struct GNUNET_PeerIdentity *peer)
89{
90 fprintf (stderr, "Disconnect: %s\n",
91 GNUNET_i2s (peer));
92}
93
94
95/**
96 * Function called if DV receives a message for this peer.
97 *
98 * @param cls closure
99 * @param sender sender of the message
100 * @param distance how far did the message travel
101 * @param msg actual message payload
102 */
103static void
104message_cb (void *cls,
105 const struct GNUNET_PeerIdentity *sender,
106 uint32_t distance,
107 const struct GNUNET_MessageHeader *msg)
108{
109 if (verbose)
110 fprintf (stderr, "Message: %s at %u sends %u bytes of type %u\n",
111 GNUNET_i2s (sender),
112 (unsigned int) distance,
113 (unsigned int) ntohs (msg->size),
114 (unsigned int) ntohs (msg->type));
115}
116
117
118/**
119 * Task run on shutdown.
120 *
121 * @param cls NULL
122 */
123static void
124shutdown_task (void *cls)
125{
126 GNUNET_DV_service_disconnect (sh);
127 sh = NULL;
128}
129
130
131/**
132 * Main function that will be run by the scheduler.
133 *
134 * @param cls closure
135 * @param args remaining command-line arguments
136 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
137 * @param cfg configuration
138 */
139static void
140run (void *cls, char *const *args, const char *cfgfile,
141 const struct GNUNET_CONFIGURATION_Handle *cfg)
142{
143 sh = GNUNET_DV_service_connect (cfg, NULL,
144 &connect_cb,
145 &change_cb,
146 &disconnect_cb,
147 &message_cb);
148 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
149}
150
151
152/**
153 * The main function.
154 *
155 * @param argc number of arguments from the command line
156 * @param argv command line arguments
157 * @return 0 ok, 1 on error
158 */
159int
160main (int argc, char *const *argv)
161{
162 int res;
163
164 struct GNUNET_GETOPT_CommandLineOption options[] = {
165
166 GNUNET_GETOPT_option_verbose (&verbose),
167
168 GNUNET_GETOPT_OPTION_END
169 };
170
171 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
172 return 2;
173
174 res = GNUNET_PROGRAM_run (argc, argv, "gnunet-dv",
175 gettext_noop ("Print information about DV state"),
176 options, &run,
177 NULL);
178 GNUNET_free ((void *) argv);
179
180 if (GNUNET_OK != res)
181 return 1;
182 return 0;
183}
184
185/* end of gnunet-dv.c */
diff --git a/src/dv/gnunet-service-dv.c b/src/dv/gnunet-service-dv.c
deleted file mode 100644
index dd2ff9c12..000000000
--- a/src/dv/gnunet-service-dv.c
+++ /dev/null
@@ -1,2146 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013, 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 dv/gnunet-service-dv.c
23 * @brief the distance vector service, primarily handles gossip of nearby
24 * peers and sending/receiving DV messages from core and decapsulating
25 * them
26 *
27 * @author Christian Grothoff
28 * @author Nathan Evans
29 */
30#include "platform.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_protocols.h"
33#include "gnunet_core_service.h"
34#include "gnunet_hello_lib.h"
35#include "gnunet_peerinfo_service.h"
36#include "gnunet_statistics_service.h"
37#include "gnunet_set_service.h"
38#include "gnunet_ats_service.h"
39#include "dv.h"
40#include <gcrypt.h>
41
42
43/**
44 * How often do we establish the consensu?
45 */
46#define GNUNET_DV_CONSENSUS_FREQUENCY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
47
48/**
49 * Maximum number of messages we queue per peer.
50 */
51#define MAX_QUEUE_SIZE 16
52
53/**
54 * Maximum number of messages we queue towards the clients/plugin.
55 */
56#define MAX_QUEUE_SIZE_PLUGIN 1024
57
58/**
59 * The default fisheye depth, from how many hops away will
60 * we keep peers?
61 */
62#define DEFAULT_FISHEYE_DEPTH 3
63
64/**
65 * How many hops is a direct neighbor away?
66 */
67#define DIRECT_NEIGHBOR_COST 1
68
69
70GNUNET_NETWORK_STRUCT_BEGIN
71
72/**
73 * Information about a peer DV can route to. These entries are what
74 * we use as the binary format to establish consensus to create our
75 * routing table and as the address format in the HELLOs.
76 */
77struct Target
78{
79
80 /**
81 * Identity of the peer we can reach.
82 */
83 struct GNUNET_PeerIdentity peer;
84
85 /**
86 * How many hops (1-3) is this peer away? in network byte order
87 */
88 uint32_t distance GNUNET_PACKED;
89
90};
91
92
93/**
94 * Message exchanged between DV services (via core), requesting a
95 * message to be routed.
96 */
97struct RouteMessage
98{
99 /**
100 * Type: #GNUNET_MESSAGE_TYPE_DV_ROUTE
101 */
102 struct GNUNET_MessageHeader header;
103
104 /**
105 * Expected (remaining) distance. Must be always smaller than
106 * #DEFAULT_FISHEYE_DEPTH, should be zero at the target. Must
107 * be decremented by one at each hop. Peers must not forward
108 * these messages further once the counter has reached zero.
109 */
110 uint32_t distance GNUNET_PACKED;
111
112 /**
113 * The (actual) target of the message (this peer, if distance is zero).
114 */
115 struct GNUNET_PeerIdentity target;
116
117 /**
118 * The (actual) sender of the message.
119 */
120 struct GNUNET_PeerIdentity sender;
121
122};
123
124GNUNET_NETWORK_STRUCT_END
125
126
127/**
128 * Information about a direct neighbor (core-level, excluding
129 * DV-links, only DV-enabled peers).
130 */
131struct DirectNeighbor
132{
133
134 /**
135 * Identity of the peer.
136 */
137 struct GNUNET_PeerIdentity peer;
138
139 /**
140 * Session ID we use whenever we create a set union with
141 * this neighbor; constructed from the XOR of our peer
142 * IDs and then salted with "DV-SALT" to avoid conflicts
143 * with other applications.
144 */
145 struct GNUNET_HashCode real_session_id;
146
147 /**
148 * Transmit handle to core service.
149 */
150 struct GNUNET_MQ_Handle *mq;
151
152 /**
153 * Routing table of the neighbor, NULL if not yet established.
154 * Keys are peer identities, values are 'struct Target' entries.
155 * Note that the distances in the targets are from the point-of-view
156 * of the peer, not from us!
157 */
158 struct GNUNET_CONTAINER_MultiPeerMap *neighbor_table;
159
160 /**
161 * Updated routing table of the neighbor, under construction,
162 * NULL if we are not currently building it.
163 * Keys are peer identities, values are 'struct Target' entries.
164 * Note that the distances in the targets are from the point-of-view
165 * of the other peer, not from us!
166 */
167 struct GNUNET_CONTAINER_MultiPeerMap *neighbor_table_consensus;
168
169 /**
170 * Our current (exposed) routing table as a set.
171 */
172 struct GNUNET_SET_Handle *my_set;
173
174 /**
175 * Handle for our current active set union operation.
176 */
177 struct GNUNET_SET_OperationHandle *set_op;
178
179 /**
180 * Handle used if we are listening for this peer, waiting for the
181 * other peer to initiate construction of the set union. NULL if
182 * we ar the initiating peer.
183 */
184 struct GNUNET_SET_ListenHandle *listen_handle;
185
186 /**
187 * ID of the task we use to (periodically) update our consensus
188 * with this peer. Used if we are the initiating peer.
189 */
190 struct GNUNET_SCHEDULER_Task *initiate_task;
191
192 /**
193 * At what offset are we, with respect to inserting our own routes
194 * into the consensus?
195 */
196 unsigned int consensus_insertion_offset;
197
198 /**
199 * At what distance are we, with respect to inserting our own routes
200 * into the consensus?
201 */
202 unsigned int consensus_insertion_distance;
203
204 /**
205 * Elements in consensus
206 */
207 unsigned int consensus_elements;
208
209 /**
210 * Direct one hop route
211 */
212 struct Route *direct_route;
213
214 /**
215 * Flag set within 'check_target_removed' to trigger full global route refresh.
216 */
217 int target_removed;
218
219 /**
220 * Our distance to this peer, 0 for unknown.
221 */
222 uint32_t distance;
223
224 /**
225 * The network this peer is in
226 */
227 enum GNUNET_NetworkType network;
228
229 /**
230 * Is this neighbor connected at the core level?
231 */
232 int connected;
233
234};
235
236
237/**
238 * A route includes information about the next hop,
239 * the target, and the ultimate distance to the
240 * target.
241 */
242struct Route
243{
244
245 /**
246 * Which peer do we need to forward the message to?
247 */
248 struct DirectNeighbor *next_hop;
249
250 /**
251 * What would be the target, and how far is it away?
252 */
253 struct Target target;
254
255 /**
256 * Offset of this target in the respective consensus set.
257 */
258 unsigned int set_offset;
259
260};
261
262
263/**
264 * Set of targets we bring to a consensus; all targets in a set have a
265 * distance equal to the sets distance (which is implied by the array
266 * index of the set).
267 */
268struct ConsensusSet
269{
270
271 /**
272 * Array of targets in the set, may include NULL entries if a
273 * neighbor has disconnected; the targets are allocated with the
274 * respective container (all_routes), not here.
275 */
276 struct Route **targets;
277
278 /**
279 * Size of the @e targets array.
280 */
281 unsigned int array_length;
282
283};
284
285
286/**
287 * Peermap of all of our neighbors; processing these usually requires
288 * first checking to see if the peer is core-connected and if the
289 * distance is 1, in which case they are direct neighbors.
290 */
291static struct GNUNET_CONTAINER_MultiPeerMap *direct_neighbors;
292
293/**
294 * Hashmap with all routes that we currently support; contains
295 * routing information for all peers from distance 2
296 * up to distance #DEFAULT_FISHEYE_DEPTH.
297 */
298static struct GNUNET_CONTAINER_MultiPeerMap *all_routes;
299
300/**
301 * Array of consensus sets we expose to the outside world. Sets
302 * are structured by the distance to the target.
303 */
304static struct ConsensusSet consensi[DEFAULT_FISHEYE_DEPTH];
305
306/**
307 * Handle to the core service api.
308 */
309static struct GNUNET_CORE_Handle *core_api;
310
311/**
312 * The identity of our peer.
313 */
314static struct GNUNET_PeerIdentity my_identity;
315
316/**
317 * The configuration for this service.
318 */
319static const struct GNUNET_CONFIGURATION_Handle *cfg;
320
321/**
322 * The client, the DV plugin connected to us (or an event monitor).
323 * Hopefully this client will never change, although if the plugin
324 * dies and returns for some reason it may happen.
325 */
326static struct GNUNET_NotificationContext *nc;
327
328/**
329 * Handle for the statistics service.
330 */
331static struct GNUNET_STATISTICS_Handle *stats;
332
333/**
334 * Handle to ATS service.
335 */
336static struct GNUNET_ATS_PerformanceHandle *ats;
337
338/**
339 * Task scheduled to refresh routes based on direct neighbours.
340 */
341static struct GNUNET_SCHEDULER_Task *rr_task;
342
343/**
344 * #GNUNET_YES if we are shutting down.
345 */
346static int in_shutdown;
347
348/**
349 * Start creating a new DV set union by initiating the connection.
350 *
351 * @param cls the 'struct DirectNeighbor' of the peer we're building
352 * a routing consensus with
353 */
354static void
355initiate_set_union (void *cls);
356
357
358/**
359 * Start creating a new DV set union construction, our neighbour has
360 * asked for it (callback for listening peer).
361 *
362 * @param cls the 'struct DirectNeighbor' of the peer we're building
363 * a routing consensus with
364 * @param other_peer the other peer
365 * @param context_msg message with application specific information from
366 * the other peer
367 * @param request request from the other peer, use GNUNET_SET_accept
368 * to accept it, otherwise the request will be refused
369 * Note that we don't use a return value here, as it is also
370 * necessary to specify the set we want to do the operation with,
371 * whith sometimes can be derived from the context message.
372 * Also necessary to specify the timeout.
373 */
374static void
375listen_set_union (void *cls,
376 const struct GNUNET_PeerIdentity *other_peer,
377 const struct GNUNET_MessageHeader *context_msg,
378 struct GNUNET_SET_Request *request);
379
380
381/**
382 * Forward a message from another peer to the plugin.
383 *
384 * @param message the message to send to the plugin
385 * @param origin the original sender of the message
386 * @param distance distance to the original sender of the message
387 */
388static void
389send_data_to_plugin (const struct GNUNET_MessageHeader *message,
390 const struct GNUNET_PeerIdentity *origin,
391 uint32_t distance)
392{
393 struct GNUNET_DV_ReceivedMessage *received_msg;
394 size_t size;
395
396 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
397 "Delivering message from peer `%s' at distance %u\n",
398 GNUNET_i2s (origin),
399 (unsigned int) distance);
400 size = sizeof (struct GNUNET_DV_ReceivedMessage) +
401 ntohs (message->size);
402 if (size >= GNUNET_MAX_MESSAGE_SIZE)
403 {
404 GNUNET_break (0); /* too big */
405 return;
406 }
407 received_msg = GNUNET_malloc (size);
408 received_msg->header.size = htons (size);
409 received_msg->header.type = htons (GNUNET_MESSAGE_TYPE_DV_RECV);
410 received_msg->distance = htonl (distance);
411 received_msg->sender = *origin;
412 GNUNET_memcpy (&received_msg[1], message, ntohs (message->size));
413 GNUNET_notification_context_broadcast (nc,
414 &received_msg->header,
415 GNUNET_YES);
416 GNUNET_free (received_msg);
417}
418
419
420/**
421 * Forward a control message to the plugin.
422 *
423 * @param message the message to send to the plugin
424 */
425static void
426send_control_to_plugin (const struct GNUNET_MessageHeader *message)
427{
428 GNUNET_notification_context_broadcast (nc,
429 message,
430 GNUNET_NO);
431}
432
433
434/**
435 * Send a DISTANCE_CHANGED message to the plugin.
436 *
437 * @param peer peer with a changed distance
438 * @param distance new distance to the peer
439 * @param network network used by the neighbor
440 */
441static void
442send_distance_change_to_plugin (const struct GNUNET_PeerIdentity *peer,
443 uint32_t distance,
444 enum GNUNET_NetworkType network)
445{
446 struct GNUNET_DV_DistanceUpdateMessage du_msg;
447
448 GNUNET_break (GNUNET_NT_UNSPECIFIED != network);
449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
450 "Delivering DISTANCE_CHANGED for message about peer `%s'\n",
451 GNUNET_i2s (peer));
452 du_msg.header.size = htons (sizeof (du_msg));
453 du_msg.header.type = htons (GNUNET_MESSAGE_TYPE_DV_DISTANCE_CHANGED);
454 du_msg.distance = htonl (distance);
455 du_msg.peer = *peer;
456 du_msg.network = htonl ((uint32_t) network);
457 send_control_to_plugin (&du_msg.header);
458}
459
460
461/**
462 * Give a CONNECT message to the plugin.
463 *
464 * @param target peer that connected
465 * @param distance distance to the target
466 * @param network the network the next hop is located in
467 */
468static void
469send_connect_to_plugin (const struct GNUNET_PeerIdentity *target,
470 uint32_t distance,
471 enum GNUNET_NetworkType network)
472{
473 struct GNUNET_DV_ConnectMessage cm;
474
475 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
476 "Delivering CONNECT about peer %s with distance %u\n",
477 GNUNET_i2s (target), distance);
478 cm.header.size = htons (sizeof (cm));
479 cm.header.type = htons (GNUNET_MESSAGE_TYPE_DV_CONNECT);
480 cm.distance = htonl (distance);
481 cm.network = htonl ((uint32_t) network);
482 cm.peer = *target;
483 send_control_to_plugin (&cm.header);
484}
485
486
487/**
488 * Give a DISCONNECT message to the plugin.
489 *
490 * @param target peer that disconnected
491 */
492static void
493send_disconnect_to_plugin (const struct GNUNET_PeerIdentity *target)
494{
495 struct GNUNET_DV_DisconnectMessage dm;
496
497 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
498 "Delivering DISCONNECT about peer `%s'\n",
499 GNUNET_i2s (target));
500 dm.header.size = htons (sizeof (dm));
501 dm.header.type = htons (GNUNET_MESSAGE_TYPE_DV_DISCONNECT);
502 dm.reserved = htonl (0);
503 dm.peer = *target;
504 send_control_to_plugin (&dm.header);
505}
506
507
508/**
509 * Forward the given payload to the given target.
510 *
511 * @param target where to send the message
512 * @param distance distance to the @a sender
513 * @param sender original sender of the message
514 * @param actual_target ultimate recipient for the message
515 * @param payload payload of the message
516 */
517static void
518forward_payload (struct DirectNeighbor *target,
519 uint32_t distance,
520 const struct GNUNET_PeerIdentity *sender,
521 const struct GNUNET_PeerIdentity *actual_target,
522 const struct GNUNET_MessageHeader *payload)
523{
524 struct GNUNET_MQ_Envelope *env;
525 struct RouteMessage *rm;
526
527 if ( (GNUNET_MQ_get_length (target->mq) >= MAX_QUEUE_SIZE) &&
528 (0 != memcmp (sender,
529 &my_identity,
530 sizeof (struct GNUNET_PeerIdentity))) )
531 {
532 /* not _our_ client and queue is full, drop */
533 GNUNET_STATISTICS_update (stats,
534 "# messages dropped",
535 1,
536 GNUNET_NO);
537 return;
538 }
539 if (sizeof (struct RouteMessage) + ntohs (payload->size)
540 >= GNUNET_MAX_MESSAGE_SIZE)
541 {
542 GNUNET_break (0);
543 return;
544 }
545 env = GNUNET_MQ_msg_nested_mh (rm,
546 GNUNET_MESSAGE_TYPE_DV_ROUTE,
547 payload);
548 rm->distance = htonl (distance);
549 rm->target = *actual_target;
550 rm->sender = *sender;
551 GNUNET_MQ_send (target->mq,
552 env);
553}
554
555
556/**
557 * Find a free slot for storing a 'route' in the 'consensi'
558 * set at the given distance.
559 *
560 * @param distance distance to use for the set slot
561 */
562static unsigned int
563get_consensus_slot (uint32_t distance)
564{
565 struct ConsensusSet *cs;
566 unsigned int i;
567
568 GNUNET_assert (distance < DEFAULT_FISHEYE_DEPTH);
569 cs = &consensi[distance];
570 i = 0;
571 while ( (i < cs->array_length) &&
572 (NULL != cs->targets[i]) ) i++;
573 if (i == cs->array_length)
574 {
575 GNUNET_array_grow (cs->targets,
576 cs->array_length,
577 cs->array_length * 2 + 2);
578 }
579 return i;
580}
581
582
583/**
584 * Allocate a slot in the consensus set for a route.
585 *
586 * @param route route to initialize
587 * @param distance which consensus set to use
588 */
589static void
590allocate_route (struct Route *route,
591 uint32_t distance)
592{
593 unsigned int i;
594
595 if (distance >= DEFAULT_FISHEYE_DEPTH)
596 {
597 route->target.distance = htonl (distance);
598 route->set_offset = UINT_MAX; /* invalid slot */
599 return;
600 }
601 i = get_consensus_slot (distance);
602 route->set_offset = i;
603 consensi[distance].targets[i] = route;
604 route->target.distance = htonl (distance);
605}
606
607
608/**
609 * Release a slot in the consensus set for a route.
610 *
611 * @param route route to release the slot from
612 */
613static void
614release_route (struct Route *route)
615{
616 if (UINT_MAX == route->set_offset)
617 return;
618 GNUNET_assert (ntohl (route->target.distance) < DEFAULT_FISHEYE_DEPTH);
619 consensi[ntohl (route->target.distance)].targets[route->set_offset] = NULL;
620 route->set_offset = UINT_MAX; /* indicate invalid slot */
621}
622
623
624/**
625 * Move a route from one consensus set to another.
626 *
627 * @param route route to move
628 * @param new_distance new distance for the route (destination set)
629 */
630static void
631move_route (struct Route *route,
632 uint32_t new_distance)
633{
634 release_route (route);
635 allocate_route (route, new_distance);
636}
637
638
639/**
640 * Initialize this neighbors 'my_set' and when done give
641 * it to the pending set operation for execution.
642 *
643 * Add a single element to the set per call:
644 *
645 * If we reached the last element of a consensus element: increase distance
646 *
647 *
648 * @param cls the neighbor for which we are building the set
649 */
650static void
651build_set (void *cls)
652{
653 struct DirectNeighbor *neighbor = cls;
654 struct GNUNET_SET_Element element;
655 struct Target *target;
656 struct Route *route;
657
658 target = NULL;
659 /* skip over NULL entries */
660 while ( (DEFAULT_FISHEYE_DEPTH > neighbor->consensus_insertion_distance) &&
661 (consensi[neighbor->consensus_insertion_distance].array_length > neighbor->consensus_insertion_offset) &&
662 (NULL == consensi[neighbor->consensus_insertion_distance].targets[neighbor->consensus_insertion_offset]) )
663 neighbor->consensus_insertion_offset++;
664 while ( (DEFAULT_FISHEYE_DEPTH > neighbor->consensus_insertion_distance) &&
665 (consensi[neighbor->consensus_insertion_distance].array_length == neighbor->consensus_insertion_offset) )
666 {
667 /* If we reached the last element of a consensus array element: increase distance and start with next array */
668 neighbor->consensus_insertion_offset = 0;
669 neighbor->consensus_insertion_distance++;
670 /* skip over NULL entries */
671 while ( (DEFAULT_FISHEYE_DEPTH > neighbor->consensus_insertion_distance) &&
672 (consensi[neighbor->consensus_insertion_distance].array_length > neighbor->consensus_insertion_offset) &&
673 (NULL == consensi[neighbor->consensus_insertion_distance].targets[neighbor->consensus_insertion_offset]) )
674 neighbor->consensus_insertion_offset++;
675 }
676 if (DEFAULT_FISHEYE_DEPTH == neighbor->consensus_insertion_distance)
677 {
678 /* we have added all elements to the set, run the operation */
679 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
680 "Finished building my SET for peer `%s' with %u elements, committing\n",
681 GNUNET_i2s (&neighbor->peer),
682 neighbor->consensus_elements);
683 GNUNET_SET_commit (neighbor->set_op,
684 neighbor->my_set);
685 GNUNET_SET_destroy (neighbor->my_set);
686 neighbor->my_set = NULL;
687 return;
688 }
689
690 route = consensi[neighbor->consensus_insertion_distance].targets[neighbor->consensus_insertion_offset];
691 GNUNET_assert (NULL != route);
692 target = &route->target;
693 GNUNET_assert (ntohl (target->distance) < DEFAULT_FISHEYE_DEPTH);
694 element.size = sizeof (struct Target);
695 element.element_type = htons (0);
696 element.data = target;
697
698 /* Find next non-NULL entry */
699 neighbor->consensus_insertion_offset++;
700 if ( (0 != memcmp (&target->peer,
701 &my_identity,
702 sizeof (my_identity))) &&
703 (0 != memcmp (&target->peer,
704 &neighbor->peer,
705 sizeof (struct GNUNET_PeerIdentity))) )
706 {
707 /* Add target if it is not the neighbor or this peer */
708 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
709 "Adding peer `%s' with distance %u to SET\n",
710 GNUNET_i2s (&target->peer),
711 ntohl (target->distance) + 1);
712 GNUNET_SET_add_element (neighbor->my_set,
713 &element,
714 &build_set, neighbor);
715 neighbor->consensus_elements++;
716 }
717 else
718 build_set (neighbor);
719}
720
721
722/**
723 * A peer is now connected to us at distance 1. Initiate DV exchange.
724 *
725 * @param neighbor entry for the neighbor at distance 1
726 */
727static void
728handle_direct_connect (struct DirectNeighbor *neighbor)
729{
730 struct Route *route;
731 struct GNUNET_HashCode h1;
732 struct GNUNET_HashCode h2;
733 struct GNUNET_HashCode session_id;
734
735 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
736 "Direct connection to %s established, routing table exchange begins.\n",
737 GNUNET_i2s (&neighbor->peer));
738 GNUNET_STATISTICS_update (stats,
739 "# peers connected (1-hop)",
740 1, GNUNET_NO);
741 route = GNUNET_CONTAINER_multipeermap_get (all_routes,
742 &neighbor->peer);
743 if (NULL != route)
744 {
745 GNUNET_assert (GNUNET_YES ==
746 GNUNET_CONTAINER_multipeermap_remove (all_routes,
747 &neighbor->peer,
748 route));
749 send_disconnect_to_plugin (&neighbor->peer);
750 release_route (route);
751 GNUNET_free (route);
752 }
753
754 neighbor->direct_route = GNUNET_new (struct Route);
755 neighbor->direct_route->next_hop = neighbor;
756 neighbor->direct_route->target.peer = neighbor->peer;
757 allocate_route (neighbor->direct_route, DIRECT_NEIGHBOR_COST);
758
759 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
760 "Adding direct route to %s\n",
761 GNUNET_i2s (&neighbor->direct_route->target.peer));
762
763
764 /* construct session ID seed as XOR of both peer's identities */
765 GNUNET_CRYPTO_hash (&my_identity,
766 sizeof (my_identity),
767 &h1);
768 GNUNET_CRYPTO_hash (&neighbor->peer,
769 sizeof (struct GNUNET_PeerIdentity),
770 &h2);
771 GNUNET_CRYPTO_hash_xor (&h1,
772 &h2,
773 &session_id);
774 /* make sure session ID is unique across applications by salting it with 'DV' */
775 GNUNET_CRYPTO_hkdf (&neighbor->real_session_id, sizeof (struct GNUNET_HashCode),
776 GCRY_MD_SHA512, GCRY_MD_SHA256,
777 "DV-SALT", 2,
778 &session_id, sizeof (session_id),
779 NULL, 0);
780 if (0 < memcmp (&neighbor->peer,
781 &my_identity,
782 sizeof (struct GNUNET_PeerIdentity)))
783 {
784 if (NULL != neighbor->listen_handle)
785 {
786 GNUNET_break (0);
787 }
788 else
789 neighbor->initiate_task = GNUNET_SCHEDULER_add_now (&initiate_set_union,
790 neighbor);
791 }
792 else
793 {
794 if (NULL != neighbor->listen_handle)
795 {
796 GNUNET_break (0);
797 }
798 else
799 {
800 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
801 "Starting SET listen operation with peer `%s'\n",
802 GNUNET_i2s (&neighbor->peer));
803 neighbor->listen_handle = GNUNET_SET_listen (cfg,
804 GNUNET_SET_OPERATION_UNION,
805 &neighbor->real_session_id,
806 &listen_set_union,
807 neighbor);
808 }
809 }
810}
811
812
813/**
814 * Method called whenever a peer connects.
815 *
816 * @param cls closure
817 * @param peer peer identity this notification is about
818 * @param mq message queue for sending data to @a peer
819 * @return our `struct DirectNeighbour` for this peer
820 */
821static void *
822handle_core_connect (void *cls,
823 const struct GNUNET_PeerIdentity *peer,
824 struct GNUNET_MQ_Handle *mq)
825{
826 struct DirectNeighbor *neighbor;
827
828 /* Check for connect to self message */
829 if (0 == memcmp (&my_identity,
830 peer,
831 sizeof (struct GNUNET_PeerIdentity)))
832 return NULL;
833 /* check if entry exists */
834 neighbor = GNUNET_CONTAINER_multipeermap_get (direct_neighbors,
835 peer);
836 if (NULL != neighbor)
837 {
838 GNUNET_break (GNUNET_NT_UNSPECIFIED != neighbor->network);
839 GNUNET_break (GNUNET_YES != neighbor->connected);
840 neighbor->connected = GNUNET_YES;
841 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
842 "Core connected to %s (distance %u)\n",
843 GNUNET_i2s (peer),
844 (unsigned int) neighbor->distance);
845 if (DIRECT_NEIGHBOR_COST != neighbor->distance)
846 return NULL;
847 handle_direct_connect (neighbor);
848 return NULL;
849 }
850 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
851 "Core connected to %s (distance unknown)\n",
852 GNUNET_i2s (peer));
853 neighbor = GNUNET_new (struct DirectNeighbor);
854 neighbor->peer = *peer;
855 GNUNET_assert (GNUNET_YES ==
856 GNUNET_CONTAINER_multipeermap_put (direct_neighbors,
857 &neighbor->peer,
858 neighbor,
859 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
860 neighbor->connected = GNUNET_YES;
861 neighbor->distance = 0; /* unknown */
862 neighbor->network = GNUNET_NT_UNSPECIFIED;
863 return neighbor;
864}
865
866
867/**
868 * Called for each 'target' in a neighbor table to free the associated memory.
869 *
870 * @param cls NULL
871 * @param key key of the value
872 * @param value value to free
873 * @return #GNUNET_OK to continue to iterate
874 */
875static int
876free_targets (void *cls,
877 const struct GNUNET_PeerIdentity *key,
878 void *value)
879{
880 GNUNET_free (value);
881 return GNUNET_OK;
882}
883
884
885/**
886 * Add a new route to the given @a target via the given @a neighbor.
887 *
888 * @param target the target of the route
889 * @param neighbor the next hop for communicating with the @a target
890 */
891static void
892add_new_route (struct Target *target,
893 struct DirectNeighbor *neighbor)
894{
895 struct Route *route;
896
897 route = GNUNET_new (struct Route);
898 route->next_hop = neighbor;
899 route->target.peer = target->peer;
900 allocate_route (route, ntohl (target->distance) + 1);
901 GNUNET_assert (GNUNET_YES ==
902 GNUNET_CONTAINER_multipeermap_put (all_routes,
903 &route->target.peer,
904 route,
905 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
906 send_connect_to_plugin (&route->target.peer,
907 ntohl (route->target.distance),
908 neighbor->network);
909}
910
911
912/**
913 * Multipeerhmap iterator for checking if a given route is
914 * (now) useful to this peer.
915 *
916 * @param cls the direct neighbor for the given route
917 * @param key key value stored under
918 * @param value a 'struct Target' that may or may not be useful; not that
919 * the distance in 'target' does not include the first hop yet
920 * @return #GNUNET_YES to continue iteration, #GNUNET_NO to stop
921 */
922static int
923check_possible_route (void *cls,
924 const struct GNUNET_PeerIdentity *key,
925 void *value)
926{
927 struct DirectNeighbor *neighbor = cls;
928 struct Target *target = value;
929 struct Route *route;
930
931 if (GNUNET_YES ==
932 GNUNET_CONTAINER_multipeermap_contains (direct_neighbors,
933 key))
934 return GNUNET_YES; /* direct route, do not care about alternatives */
935 route = GNUNET_CONTAINER_multipeermap_get (all_routes,
936 key);
937 if (NULL != route)
938 {
939 /* we have an existing route, check how it compares with going via 'target' */
940 if (ntohl (route->target.distance) > ntohl (target->distance) + 1)
941 {
942 /* via 'target' is cheaper than the existing route; switch to alternative route! */
943 move_route (route, ntohl (target->distance) + 1);
944 route->next_hop = neighbor;
945 send_distance_change_to_plugin (&target->peer,
946 ntohl (target->distance) + 1,
947 neighbor->network);
948 }
949 return GNUNET_YES; /* got a route to this target already */
950 }
951 if (ntohl (target->distance) >= DEFAULT_FISHEYE_DEPTH)
952 return GNUNET_YES; /* distance is too large to be interesting */
953 add_new_route (target, neighbor);
954 return GNUNET_YES;
955}
956
957
958/**
959 * Multipeermap iterator for finding routes that were previously
960 * "hidden" due to a better route (called after a disconnect event).
961 *
962 * @param cls NULL
963 * @param key peer identity of the given direct neighbor
964 * @param value a `struct DirectNeighbor` to check for additional routes
965 * @return #GNUNET_YES to continue iteration
966 */
967static int
968refresh_routes (void *cls,
969 const struct GNUNET_PeerIdentity *key,
970 void *value)
971{
972 struct DirectNeighbor *neighbor = value;
973
974 if ( (GNUNET_YES != neighbor->connected) ||
975 (DIRECT_NEIGHBOR_COST != neighbor->distance) )
976 return GNUNET_YES;
977 if (NULL != neighbor->neighbor_table)
978 GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table,
979 &check_possible_route,
980 neighbor);
981 return GNUNET_YES;
982}
983
984
985/**
986 * Task to run #refresh_routes() on all direct neighbours.
987 *
988 * @param cls NULL
989 */
990static void
991refresh_routes_task (void *cls)
992{
993 rr_task = NULL;
994 GNUNET_CONTAINER_multipeermap_iterate (direct_neighbors,
995 &refresh_routes,
996 NULL);
997}
998
999
1000/**
1001 * Asynchronously run #refresh_routes() at the next opportunity
1002 * on all direct neighbours.
1003 */
1004static void
1005schedule_refresh_routes ()
1006{
1007 if (NULL == rr_task)
1008 rr_task = GNUNET_SCHEDULER_add_now (&refresh_routes_task,
1009 NULL);
1010}
1011
1012
1013/**
1014 * Multipeermap iterator for freeing routes that go via a particular
1015 * neighbor that disconnected and is thus no longer available.
1016 *
1017 * @param cls the direct neighbor that is now unavailable
1018 * @param key key value stored under
1019 * @param value a `struct Route` that may or may not go via neighbor
1020 *
1021 * @return #GNUNET_YES to continue iteration, #GNUNET_NO to stop
1022 */
1023static int
1024cull_routes (void *cls,
1025 const struct GNUNET_PeerIdentity *key,
1026 void *value)
1027{
1028 struct DirectNeighbor *neighbor = cls;
1029 struct Route *route = value;
1030
1031 if (route->next_hop != neighbor)
1032 return GNUNET_YES; /* not affected */
1033 GNUNET_assert (GNUNET_YES ==
1034 GNUNET_CONTAINER_multipeermap_remove (all_routes, key, value));
1035 release_route (route);
1036 send_disconnect_to_plugin (&route->target.peer);
1037 GNUNET_free (route);
1038 return GNUNET_YES;
1039}
1040
1041
1042/**
1043 * Handle the case that a direct connection to a peer is
1044 * disrupted. Remove all routes via that peer and
1045 * stop the consensus with it.
1046 *
1047 * @param neighbor peer that was disconnected (or at least is no
1048 * longer at distance 1)
1049 */
1050static void
1051handle_direct_disconnect (struct DirectNeighbor *neighbor)
1052{
1053 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1054 "Culling routes via %s due to direct disconnect\n",
1055 GNUNET_i2s (&neighbor->peer));
1056 GNUNET_CONTAINER_multipeermap_iterate (all_routes,
1057 &cull_routes,
1058 neighbor);
1059 if (NULL != neighbor->direct_route)
1060 {
1061 release_route (neighbor->direct_route);
1062 GNUNET_free (neighbor->direct_route);
1063 neighbor->direct_route = NULL;
1064 }
1065 if (NULL != neighbor->neighbor_table_consensus)
1066 {
1067 GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table_consensus,
1068 &free_targets,
1069 NULL);
1070 GNUNET_CONTAINER_multipeermap_destroy (neighbor->neighbor_table_consensus);
1071 neighbor->neighbor_table_consensus = NULL;
1072 }
1073 if (NULL != neighbor->neighbor_table)
1074 {
1075 GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table,
1076 &free_targets,
1077 NULL);
1078 GNUNET_CONTAINER_multipeermap_destroy (neighbor->neighbor_table);
1079 neighbor->neighbor_table = NULL;
1080 }
1081 if (NULL != neighbor->set_op)
1082 {
1083 GNUNET_SET_operation_cancel (neighbor->set_op);
1084 neighbor->set_op = NULL;
1085 }
1086 if (NULL != neighbor->my_set)
1087 {
1088 GNUNET_SET_destroy (neighbor->my_set);
1089 neighbor->my_set = NULL;
1090 }
1091 if (NULL != neighbor->listen_handle)
1092 {
1093 GNUNET_SET_listen_cancel (neighbor->listen_handle);
1094 neighbor->listen_handle = NULL;
1095 }
1096 if (NULL != neighbor->initiate_task)
1097 {
1098 GNUNET_SCHEDULER_cancel (neighbor->initiate_task);
1099 neighbor->initiate_task = NULL;
1100 }
1101}
1102
1103
1104/**
1105 * Function that is called with QoS information about an address; used
1106 * to update our current distance to another peer.
1107 *
1108 * @param cls closure
1109 * @param address the address
1110 * @param active #GNUNET_YES if this address is actively used
1111 * to maintain a connection to a peer;
1112 * #GNUNET_NO if the address is not actively used;
1113 * #GNUNET_SYSERR if this address is no longer available for ATS
1114 * @param bandwidth_out assigned outbound bandwidth for the connection
1115 * @param bandwidth_in assigned inbound bandwidth for the connection
1116 * @param prop performance data for the address (as far as known)
1117 */
1118static void
1119handle_ats_update (void *cls,
1120 const struct GNUNET_HELLO_Address *address,
1121 int active,
1122 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
1123 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
1124 const struct GNUNET_ATS_Properties *prop)
1125{
1126 struct DirectNeighbor *neighbor;
1127 uint32_t distance;
1128 enum GNUNET_NetworkType network;
1129
1130 if (NULL == address)
1131 {
1132 /* ATS service temporarily disconnected */
1133 return;
1134 }
1135
1136 if (GNUNET_YES != active)
1137 {
1138 // FIXME: handle disconnect/inactive case too!
1139 return;
1140 }
1141 distance = prop->distance;
1142 network = prop->scope;
1143 GNUNET_break (GNUNET_NT_UNSPECIFIED != network);
1144 /* check if entry exists */
1145 neighbor = GNUNET_CONTAINER_multipeermap_get (direct_neighbors,
1146 &address->peer);
1147 if (NULL != neighbor)
1148 {
1149 neighbor->network = network;
1150 if (neighbor->distance == distance)
1151 return; /* nothing new to see here, move along */
1152 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1153 "ATS says distance to %s is now %u\n",
1154 GNUNET_i2s (&address->peer),
1155 (unsigned int) distance);
1156 if ( (DIRECT_NEIGHBOR_COST == neighbor->distance) &&
1157 (DIRECT_NEIGHBOR_COST == distance) )
1158 return; /* no change */
1159 if (DIRECT_NEIGHBOR_COST == neighbor->distance)
1160 {
1161 neighbor->distance = distance;
1162 GNUNET_STATISTICS_update (stats,
1163 "# peers connected (1-hop)",
1164 -1, GNUNET_NO);
1165 handle_direct_disconnect (neighbor);
1166 schedule_refresh_routes ();
1167 return;
1168 }
1169 neighbor->distance = distance;
1170 if (DIRECT_NEIGHBOR_COST != neighbor->distance)
1171 return;
1172 if (GNUNET_YES != neighbor->connected)
1173 return;
1174 handle_direct_connect (neighbor);
1175 return;
1176 }
1177 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1178 "ATS says distance to %s is now %u\n",
1179 GNUNET_i2s (&address->peer),
1180 (unsigned int) distance);
1181 neighbor = GNUNET_new (struct DirectNeighbor);
1182 neighbor->peer = address->peer;
1183 GNUNET_assert (GNUNET_YES ==
1184 GNUNET_CONTAINER_multipeermap_put (direct_neighbors,
1185 &neighbor->peer,
1186 neighbor,
1187 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1188 neighbor->connected = GNUNET_NO; /* not yet */
1189 neighbor->distance = distance;
1190 neighbor->network = network;
1191}
1192
1193
1194/**
1195 * Check if a target was removed from the set of the other peer; if so,
1196 * if we also used it for our route, we need to remove it from our
1197 * 'all_routes' set (and later check if an alternative path now exists).
1198 *
1199 * @param cls the `struct DirectNeighbor`
1200 * @param key peer identity for the target
1201 * @param value a `struct Target` previously reachable via the given neighbor
1202 */
1203static int
1204check_target_removed (void *cls,
1205 const struct GNUNET_PeerIdentity *key,
1206 void *value)
1207{
1208 struct DirectNeighbor *neighbor = cls;
1209 struct Target *new_target;
1210 struct Route *current_route;
1211
1212 new_target = GNUNET_CONTAINER_multipeermap_get (neighbor->neighbor_table_consensus,
1213 key);
1214 current_route = GNUNET_CONTAINER_multipeermap_get (all_routes,
1215 key);
1216 if (NULL != new_target)
1217 {
1218 /* target was in old set, is in new set */
1219 if ( (NULL != current_route) &&
1220 (current_route->next_hop == neighbor) &&
1221 (current_route->target.distance != new_target->distance) )
1222 {
1223 /* need to recalculate routes due to distance change */
1224 neighbor->target_removed = GNUNET_YES;
1225 }
1226 return GNUNET_OK;
1227 }
1228 /* target was revoked, check if it was used */
1229 if ( (NULL == current_route) ||
1230 (current_route->next_hop != neighbor) )
1231 {
1232 /* didn't matter, wasn't used */
1233 return GNUNET_OK;
1234 }
1235 /* remove existing route */
1236 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1237 "Lost route to %s\n",
1238 GNUNET_i2s (&current_route->target.peer));
1239 GNUNET_assert (GNUNET_YES ==
1240 GNUNET_CONTAINER_multipeermap_remove (all_routes, key, current_route));
1241 send_disconnect_to_plugin (&current_route->target.peer);
1242 release_route (current_route);
1243 GNUNET_free (current_route);
1244 neighbor->target_removed = GNUNET_YES;
1245 return GNUNET_OK;
1246}
1247
1248
1249/**
1250 * Check if a target was added to the set of the other peer; if it
1251 * was added or impoves the existing route, do the needed updates.
1252 *
1253 * @param cls the `struct DirectNeighbor`
1254 * @param key peer identity for the target
1255 * @param value a `struct Target` now reachable via the given neighbor
1256 */
1257static int
1258check_target_added (void *cls,
1259 const struct GNUNET_PeerIdentity *key,
1260 void *value)
1261{
1262 struct DirectNeighbor *neighbor = cls;
1263 struct Target *target = value;
1264 struct Route *current_route;
1265
1266 /* target was revoked, check if it was used */
1267 current_route = GNUNET_CONTAINER_multipeermap_get (all_routes,
1268 key);
1269 if (NULL != current_route)
1270 {
1271 /* route exists */
1272 if (current_route->next_hop == neighbor)
1273 {
1274 /* we had the same route before, no change in target */
1275 if (ntohl (target->distance) + 1 != ntohl (current_route->target.distance))
1276 {
1277 /* but distance changed! */
1278 if (ntohl (target->distance) + 1 > DEFAULT_FISHEYE_DEPTH)
1279 {
1280 /* distance increased beyond what is allowed, kill route */
1281 GNUNET_assert (GNUNET_YES ==
1282 GNUNET_CONTAINER_multipeermap_remove (all_routes,
1283 key,
1284 current_route));
1285 send_disconnect_to_plugin (key);
1286 release_route (current_route);
1287 GNUNET_free (current_route);
1288 }
1289 else
1290 {
1291 /* distance decreased, update route */
1292 move_route (current_route,
1293 ntohl (target->distance) + 1);
1294 send_distance_change_to_plugin (&target->peer,
1295 ntohl (target->distance) + 1,
1296 neighbor->network);
1297 }
1298 }
1299 return GNUNET_OK;
1300 }
1301 if (ntohl (current_route->target.distance) <= ntohl (target->distance) + 1)
1302 {
1303 /* alternative, shorter route exists, ignore */
1304 return GNUNET_OK;
1305 }
1306 /* new route is better than the existing one, take over! */
1307 /* NOTE: minor security issue: malicious peers may advertise
1308 very short routes to take over longer paths; as we don't
1309 check that the shorter routes actually work, a malicious
1310 direct neighbor can use this to DoS our long routes */
1311
1312 move_route (current_route, ntohl (target->distance) + 1);
1313 current_route->next_hop = neighbor;
1314 send_distance_change_to_plugin (&target->peer,
1315 ntohl (target->distance) + 1,
1316 neighbor->network);
1317 return GNUNET_OK;
1318 }
1319 /* new route */
1320 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1321 "Discovered new route to %s using %u hops\n",
1322 GNUNET_i2s (&target->peer),
1323 (unsigned int) (ntohl (target->distance) + 1));
1324 current_route = GNUNET_new (struct Route);
1325 current_route->next_hop = neighbor;
1326 current_route->target.peer = target->peer;
1327 allocate_route (current_route, ntohl (target->distance) + 1);
1328 GNUNET_assert (GNUNET_YES ==
1329 GNUNET_CONTAINER_multipeermap_put (all_routes,
1330 &current_route->target.peer,
1331 current_route,
1332 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1333
1334 send_connect_to_plugin (&current_route->target.peer,
1335 ntohl (current_route->target.distance),
1336 neighbor->network);
1337 return GNUNET_OK;
1338}
1339
1340
1341/**
1342 * Callback for set operation results. Called for each element
1343 * in the result set.
1344 * We have learned a new route from the other peer. Add it to the
1345 * route set we're building.
1346 *
1347 * @param cls the `struct DirectNeighbor` we're building the consensus with
1348 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
1349 * @param current_size current set size
1350 * @param status see `enum GNUNET_SET_Status`
1351 */
1352static void
1353handle_set_union_result (void *cls,
1354 const struct GNUNET_SET_Element *element,
1355 uint64_t current_size,
1356 enum GNUNET_SET_Status status)
1357{
1358 struct DirectNeighbor *neighbor = cls;
1359 struct DirectNeighbor *dn;
1360 struct Target *target;
1361 const struct Target *ctarget;
1362 char *status_str;
1363
1364 switch (status)
1365 {
1366 case GNUNET_SET_STATUS_OK:
1367 status_str = "GNUNET_SET_STATUS_OK";
1368 break;
1369 case GNUNET_SET_STATUS_FAILURE:
1370 status_str = "GNUNET_SET_STATUS_FAILURE";
1371 break;
1372 case GNUNET_SET_STATUS_HALF_DONE:
1373 status_str = "GNUNET_SET_STATUS_HALF_DONE";
1374 break;
1375 case GNUNET_SET_STATUS_DONE:
1376 status_str = "GNUNET_SET_STATUS_DONE";
1377 break;
1378 default:
1379 status_str = "UNDEFINED";
1380 break;
1381 }
1382
1383 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1384 "Got SET union result: %s\n",
1385 status_str);
1386 switch (status)
1387 {
1388 case GNUNET_SET_STATUS_OK:
1389 if (sizeof (struct Target) != element->size)
1390 {
1391 GNUNET_break_op (0);
1392 return;
1393 }
1394 ctarget = element->data;
1395 if ( (NULL !=
1396 (dn = GNUNET_CONTAINER_multipeermap_get (direct_neighbors,
1397 &ctarget->peer))) &&
1398 (DIRECT_NEIGHBOR_COST == dn->distance) )
1399 {
1400 /* this is a direct neighbor of ours, we do not care about routes
1401 to this peer */
1402 return;
1403 }
1404 target = GNUNET_new (struct Target);
1405 GNUNET_memcpy (target, element->data, sizeof (struct Target));
1406 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1407 "Received information about peer `%s' with distance %u from SET\n",
1408 GNUNET_i2s (&target->peer),
1409 ntohl (target->distance) + 1);
1410
1411 if (NULL == neighbor->neighbor_table_consensus)
1412 neighbor->neighbor_table_consensus
1413 = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1414 if (GNUNET_YES !=
1415 GNUNET_CONTAINER_multipeermap_put (neighbor->neighbor_table_consensus,
1416 &target->peer,
1417 target,
1418 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1419 {
1420 GNUNET_break_op (0);
1421 GNUNET_free (target);
1422 }
1423 break;
1424 case GNUNET_SET_STATUS_FAILURE:
1425 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1426 "Failed to establish DV union, will try again later\n");
1427 neighbor->set_op = NULL;
1428 if (NULL != neighbor->neighbor_table_consensus)
1429 {
1430 GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table_consensus,
1431 &free_targets,
1432 NULL);
1433 GNUNET_CONTAINER_multipeermap_destroy (neighbor->neighbor_table_consensus);
1434 neighbor->neighbor_table_consensus = NULL;
1435 }
1436 if (0 < memcmp (&neighbor->peer,
1437 &my_identity,
1438 sizeof (struct GNUNET_PeerIdentity)))
1439 neighbor->initiate_task = GNUNET_SCHEDULER_add_delayed (GNUNET_DV_CONSENSUS_FREQUENCY,
1440 &initiate_set_union,
1441 neighbor);
1442 break;
1443 case GNUNET_SET_STATUS_HALF_DONE:
1444 break;
1445 case GNUNET_SET_STATUS_DONE:
1446 /* we got all of our updates; integrate routing table! */
1447 neighbor->target_removed = GNUNET_NO;
1448 if (NULL == neighbor->neighbor_table_consensus)
1449 neighbor->neighbor_table_consensus = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1450 if (NULL != neighbor->neighbor_table)
1451 GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table,
1452 &check_target_removed,
1453 neighbor);
1454 if (GNUNET_YES == neighbor->target_removed)
1455 {
1456 /* check if we got an alternative for the removed routes */
1457 schedule_refresh_routes ();
1458 }
1459 /* add targets that appeared (and check for improved routes) */
1460 GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table_consensus,
1461 &check_target_added,
1462 neighbor);
1463 if (NULL != neighbor->neighbor_table)
1464 {
1465 GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table,
1466 &free_targets,
1467 NULL);
1468 GNUNET_CONTAINER_multipeermap_destroy (neighbor->neighbor_table);
1469 neighbor->neighbor_table = NULL;
1470 }
1471 neighbor->neighbor_table = neighbor->neighbor_table_consensus;
1472 neighbor->neighbor_table_consensus = NULL;
1473
1474 /* operation done, schedule next run! */
1475 neighbor->set_op = NULL;
1476 if (0 < memcmp (&neighbor->peer,
1477 &my_identity,
1478 sizeof (struct GNUNET_PeerIdentity)))
1479 neighbor->initiate_task = GNUNET_SCHEDULER_add_delayed (GNUNET_DV_CONSENSUS_FREQUENCY,
1480 &initiate_set_union,
1481 neighbor);
1482 break;
1483 default:
1484 GNUNET_break (0);
1485 return;
1486 }
1487}
1488
1489
1490/**
1491 * Start creating a new DV set union construction, our neighbour has
1492 * asked for it (callback for listening peer).
1493 *
1494 * @param cls the 'struct DirectNeighbor' of the peer we're building
1495 * a routing consensus with
1496 * @param other_peer the other peer
1497 * @param context_msg message with application specific information from
1498 * the other peer
1499 * @param request request from the other peer, use GNUNET_SET_accept
1500 * to accept it, otherwise the request will be refused
1501 * Note that we don't use a return value here, as it is also
1502 * necessary to specify the set we want to do the operation with,
1503 * whith sometimes can be derived from the context message.
1504 * Also necessary to specify the timeout.
1505 */
1506static void
1507listen_set_union (void *cls,
1508 const struct GNUNET_PeerIdentity *other_peer,
1509 const struct GNUNET_MessageHeader *context_msg,
1510 struct GNUNET_SET_Request *request)
1511{
1512 struct DirectNeighbor *neighbor = cls;
1513
1514 if (NULL == request)
1515 return; /* why??? */
1516 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1517 "Starting to create consensus with %s\n",
1518 GNUNET_i2s (&neighbor->peer));
1519 if (NULL != neighbor->set_op)
1520 {
1521 GNUNET_SET_operation_cancel (neighbor->set_op);
1522 neighbor->set_op = NULL;
1523 }
1524 if (NULL != neighbor->my_set)
1525 {
1526 GNUNET_SET_destroy (neighbor->my_set);
1527 neighbor->my_set = NULL;
1528 }
1529 neighbor->my_set = GNUNET_SET_create (cfg,
1530 GNUNET_SET_OPERATION_UNION);
1531 neighbor->set_op = GNUNET_SET_accept (request,
1532 GNUNET_SET_RESULT_ADDED,
1533 (struct GNUNET_SET_Option[]) {{ 0 }},
1534 &handle_set_union_result,
1535 neighbor);
1536 neighbor->consensus_insertion_offset = 0;
1537 neighbor->consensus_insertion_distance = 0;
1538 neighbor->consensus_elements = 0;
1539 build_set (neighbor);
1540}
1541
1542
1543/**
1544 * Start creating a new DV set union by initiating the connection.
1545 *
1546 * @param cls the `struct DirectNeighbor *` of the peer we're building
1547 * a routing consensus with
1548 */
1549static void
1550initiate_set_union (void *cls)
1551{
1552 struct DirectNeighbor *neighbor = cls;
1553
1554 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1555 "Initiating SET union with peer `%s'\n",
1556 GNUNET_i2s (&neighbor->peer));
1557 neighbor->initiate_task = NULL;
1558 neighbor->my_set = GNUNET_SET_create (cfg,
1559 GNUNET_SET_OPERATION_UNION);
1560 neighbor->set_op = GNUNET_SET_prepare (&neighbor->peer,
1561 &neighbor->real_session_id,
1562 NULL,
1563 GNUNET_SET_RESULT_ADDED,
1564 (struct GNUNET_SET_Option[]) {{ 0 }},
1565 &handle_set_union_result,
1566 neighbor);
1567 neighbor->consensus_insertion_offset = 0;
1568 neighbor->consensus_insertion_distance = 0;
1569 neighbor->consensus_elements = 0;
1570 build_set (neighbor);
1571}
1572
1573
1574/**
1575 * Check that @a rm is well-formed.
1576 *
1577 * @param cls closure
1578 * @param rm the message
1579 * @return #GNUNET_OK if @a rm is well-formed.
1580 */
1581static int
1582check_dv_route_message (void *cls,
1583 const struct RouteMessage *rm)
1584{
1585 const struct GNUNET_MessageHeader *payload;
1586
1587 if (ntohs (rm->header.size) < sizeof (struct RouteMessage) + sizeof (struct GNUNET_MessageHeader))
1588 {
1589 GNUNET_break_op (0);
1590 return GNUNET_SYSERR;
1591 }
1592 payload = (const struct GNUNET_MessageHeader *) &rm[1];
1593 if (ntohs (rm->header.size) != sizeof (struct RouteMessage) + ntohs (payload->size))
1594 {
1595 GNUNET_break_op (0);
1596 return GNUNET_SYSERR;
1597 }
1598 return GNUNET_OK;
1599}
1600
1601
1602/**
1603 * Core handler for DV data messages. Whatever this message
1604 * contains all we really have to do is rip it out of its
1605 * DV layering and give it to our pal the DV plugin to report
1606 * in with.
1607 *
1608 * @param cls closure
1609 * @param rm the message
1610 */
1611static void
1612handle_dv_route_message (void *cls,
1613 const struct RouteMessage *rm)
1614{
1615 struct DirectNeighbor *neighbor = cls;
1616 const struct GNUNET_MessageHeader *payload;
1617 struct Route *route;
1618 struct DirectNeighbor *nneighbor;
1619 struct DirectNeighbor *dn;
1620 struct Target *target;
1621 uint32_t distance;
1622 char me[5];
1623 char src[5];
1624 char prev[5];
1625 char dst[5];
1626
1627 distance = ntohl (rm->distance);
1628 payload = (const struct GNUNET_MessageHeader *) &rm[1];
1629 strncpy (prev, GNUNET_i2s (&neighbor->peer), 4);
1630 strncpy (me, GNUNET_i2s (&my_identity), 4);
1631 strncpy (src, GNUNET_i2s (&rm->sender), 4);
1632 strncpy (dst, GNUNET_i2s (&rm->target), 4);
1633 prev[4] = me[4] = src[4] = dst[4] = '\0';
1634 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1635 "Handling DV message with %u bytes payload of type %u from %s to %s routed by %s to me (%s @ hop %u)\n",
1636 (unsigned int) (ntohs (rm->header.size) - sizeof (struct RouteMessage)),
1637 ntohs (payload->type),
1638 src,
1639 dst,
1640 prev,
1641 me,
1642 (unsigned int) distance + 1);
1643
1644 if (0 == memcmp (&rm->target,
1645 &my_identity,
1646 sizeof (struct GNUNET_PeerIdentity)))
1647 {
1648 if ((NULL !=
1649 (dn = GNUNET_CONTAINER_multipeermap_get (direct_neighbors,
1650 &rm->sender))) &&
1651 (DIRECT_NEIGHBOR_COST == dn->distance))
1652 {
1653 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1654 "Discarding DV message, as %s is a direct neighbor\n",
1655 GNUNET_i2s (&rm->sender));
1656 GNUNET_STATISTICS_update (stats,
1657 "# messages discarded (direct neighbor)",
1658 1, GNUNET_NO);
1659 return;
1660 }
1661 /* message is for me, check reverse route! */
1662 route = GNUNET_CONTAINER_multipeermap_get (all_routes,
1663 &rm->sender);
1664 if ( (NULL == route) &&
1665 (distance < DEFAULT_FISHEYE_DEPTH) )
1666 {
1667 /* don't have reverse route yet, learn it! */
1668 target = GNUNET_new (struct Target);
1669 target->peer = rm->sender;
1670 target->distance = htonl (distance);
1671 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1672 "Learning sender %s at distance %u from delivery!\n",
1673 GNUNET_i2s (&rm->sender),
1674 (unsigned int) distance + 1);
1675 if (NULL == neighbor->neighbor_table)
1676 neighbor->neighbor_table = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1677 if (GNUNET_YES !=
1678 GNUNET_CONTAINER_multipeermap_put (neighbor->neighbor_table,
1679 &target->peer,
1680 target,
1681 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1682 {
1683 GNUNET_break_op (0);
1684 GNUNET_free (target);
1685 return;
1686 }
1687 add_new_route (target, neighbor);
1688 }
1689 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1690 "Delivering %u bytes from %s to myself!\n",
1691 ntohs (payload->size),
1692 GNUNET_i2s (&rm->sender));
1693 send_data_to_plugin (payload,
1694 &rm->sender,
1695 1 + distance);
1696 return;
1697 }
1698 if ( (NULL == GNUNET_CONTAINER_multipeermap_get (direct_neighbors,
1699 &rm->sender)) &&
1700 (NULL == GNUNET_CONTAINER_multipeermap_get (all_routes,
1701 &rm->sender)) )
1702 {
1703 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1704 "Learning sender %s at distance %u from forwarding!\n",
1705 GNUNET_i2s (&rm->sender),
1706 1 + distance);
1707 target = GNUNET_new (struct Target);
1708 target->peer = rm->sender;
1709 target->distance = htonl (distance);
1710 if (NULL == neighbor->neighbor_table)
1711 neighbor->neighbor_table = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1712 if (GNUNET_YES !=
1713 GNUNET_CONTAINER_multipeermap_put (neighbor->neighbor_table,
1714 &target->peer,
1715 target,
1716 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1717 {
1718 GNUNET_break_op (0);
1719 GNUNET_free (target);
1720 return;
1721 }
1722 add_new_route (target, neighbor);
1723 }
1724
1725 route = GNUNET_CONTAINER_multipeermap_get (all_routes,
1726 &rm->target);
1727 if (NULL == route)
1728 {
1729 nneighbor = GNUNET_CONTAINER_multipeermap_get (direct_neighbors,
1730 &rm->target);
1731 if (NULL == nneighbor)
1732 {
1733 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1734 "No route to %s, not routing %u bytes!\n",
1735 GNUNET_i2s (&rm->target),
1736 ntohs (payload->size));
1737 GNUNET_STATISTICS_update (stats,
1738 "# messages discarded (no route)",
1739 1, GNUNET_NO);
1740 return;
1741 }
1742 }
1743 else
1744 {
1745 nneighbor = route->next_hop;
1746 }
1747 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1748 "Forwarding message to %s\n",
1749 GNUNET_i2s (&nneighbor->peer));
1750 forward_payload (nneighbor,
1751 distance + 1,
1752 &rm->sender,
1753 &rm->target,
1754 payload);
1755}
1756
1757
1758/**
1759 * Check that @a msg is well-formed
1760 *
1761 * @param cls identification of the client
1762 * @param message the actual message
1763 * @return #GNUNET_OK if @a msg is well-formed
1764 */
1765static int
1766check_dv_send_message (void *cls,
1767 const struct GNUNET_DV_SendMessage *msg)
1768{
1769 const struct GNUNET_MessageHeader *payload;
1770
1771 if (ntohs (msg->header.size) < sizeof (struct GNUNET_DV_SendMessage) +
1772 sizeof (struct GNUNET_MessageHeader))
1773 {
1774 GNUNET_break (0);
1775 return GNUNET_SYSERR;
1776 }
1777 payload = (const struct GNUNET_MessageHeader *) &msg[1];
1778 if (ntohs (msg->header.size) != sizeof (struct GNUNET_DV_SendMessage) + ntohs (payload->size))
1779 {
1780 GNUNET_break (0);
1781 return GNUNET_SYSERR;
1782 }
1783 return GNUNET_OK;
1784}
1785
1786
1787/**
1788 * Service server's handler for message send requests (which come
1789 * bubbling up to us through the DV plugin).
1790 *
1791 * @param cls identification of the client
1792 * @param message the actual message
1793 */
1794static void
1795handle_dv_send_message (void *cls,
1796 const struct GNUNET_DV_SendMessage *msg)
1797{
1798 struct GNUNET_SERVICE_Client *client = cls;
1799 struct Route *route;
1800 const struct GNUNET_MessageHeader *payload;
1801
1802 payload = (const struct GNUNET_MessageHeader *) &msg[1];
1803 route = GNUNET_CONTAINER_multipeermap_get (all_routes,
1804 &msg->target);
1805 if (NULL == route)
1806 {
1807 /* got disconnected */
1808 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1809 "No route to %s, dropping local message of type %u\n",
1810 GNUNET_i2s (&msg->target),
1811 ntohs (payload->type));
1812 GNUNET_STATISTICS_update (stats,
1813 "# local messages discarded (no route)",
1814 1, GNUNET_NO);
1815 GNUNET_SERVICE_client_continue (client);
1816 return;
1817 }
1818 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1819 "Forwarding %u bytes of type %u to %s\n",
1820 ntohs (payload->size),
1821 ntohs (payload->type),
1822 GNUNET_i2s (&msg->target));
1823
1824 forward_payload (route->next_hop,
1825 0 /* first hop, distance is zero */,
1826 &my_identity,
1827 &msg->target,
1828 payload);
1829 GNUNET_SERVICE_client_continue (client);
1830}
1831
1832
1833/**
1834 * Cleanup all of the data structures associated with a given neighbor.
1835 *
1836 * @param neighbor neighbor to clean up
1837 */
1838static void
1839cleanup_neighbor (struct DirectNeighbor *neighbor)
1840{
1841 handle_direct_disconnect (neighbor);
1842 GNUNET_assert (GNUNET_YES ==
1843 GNUNET_CONTAINER_multipeermap_remove (direct_neighbors,
1844 &neighbor->peer,
1845 neighbor));
1846 GNUNET_free (neighbor);
1847}
1848
1849
1850/**
1851 * Method called whenever a given peer disconnects.
1852 *
1853 * @param cls closure
1854 * @param peer peer identity this notification is about
1855 * @param internal_cls the corresponding `struct DirectNeighbor`
1856 */
1857static void
1858handle_core_disconnect (void *cls,
1859 const struct GNUNET_PeerIdentity *peer,
1860 void *internal_cls)
1861{
1862 struct DirectNeighbor *neighbor = internal_cls;
1863
1864 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1865 "Received core peer disconnect message for peer `%s'!\n",
1866 GNUNET_i2s (peer));
1867 /* Check for disconnect from self message */
1868 if (NULL == neighbor)
1869 return;
1870 GNUNET_break (GNUNET_YES == neighbor->connected);
1871 neighbor->connected = GNUNET_NO;
1872 if (DIRECT_NEIGHBOR_COST == neighbor->distance)
1873 {
1874 GNUNET_STATISTICS_update (stats,
1875 "# peers connected (1-hop)",
1876 -1,
1877 GNUNET_NO);
1878 }
1879 cleanup_neighbor (neighbor);
1880 if (GNUNET_YES == in_shutdown)
1881 return;
1882 schedule_refresh_routes ();
1883}
1884
1885
1886/**
1887 * Multipeermap iterator for freeing routes. Should never be called.
1888 *
1889 * @param cls NULL
1890 * @param key key value stored under
1891 * @param value the route to be freed
1892 * @return #GNUNET_YES to continue iteration, #GNUNET_NO to stop
1893 */
1894static int
1895free_route (void *cls,
1896 const struct GNUNET_PeerIdentity *key,
1897 void *value)
1898{
1899 struct Route *route = value;
1900
1901 GNUNET_break (0);
1902 GNUNET_assert (GNUNET_YES ==
1903 GNUNET_CONTAINER_multipeermap_remove (all_routes, key, value));
1904 release_route (route);
1905 send_disconnect_to_plugin (&route->target.peer);
1906 GNUNET_free (route);
1907 return GNUNET_YES;
1908}
1909
1910
1911/**
1912 * Multipeermap iterator for freeing direct neighbors. Should never be called.
1913 *
1914 * @param cls NULL
1915 * @param key key value stored under
1916 * @param value the direct neighbor to be freed
1917 * @return #GNUNET_YES to continue iteration, #GNUNET_NO to stop
1918 */
1919static int
1920free_direct_neighbors (void *cls,
1921 const struct GNUNET_PeerIdentity *key,
1922 void *value)
1923{
1924 struct DirectNeighbor *neighbor = value;
1925
1926 cleanup_neighbor (neighbor);
1927 return GNUNET_YES;
1928}
1929
1930
1931/**
1932 * Task run during shutdown.
1933 *
1934 * @param cls unused
1935 */
1936static void
1937shutdown_task (void *cls)
1938{
1939 unsigned int i;
1940
1941 in_shutdown = GNUNET_YES;
1942 GNUNET_assert (NULL != core_api);
1943 GNUNET_CORE_disconnect (core_api);
1944 core_api = NULL;
1945 GNUNET_ATS_performance_done (ats);
1946 ats = NULL;
1947 GNUNET_CONTAINER_multipeermap_iterate (direct_neighbors,
1948 &free_direct_neighbors,
1949 NULL);
1950 GNUNET_CONTAINER_multipeermap_iterate (all_routes,
1951 &free_route,
1952 NULL);
1953 GNUNET_CONTAINER_multipeermap_destroy (direct_neighbors);
1954 GNUNET_CONTAINER_multipeermap_destroy (all_routes);
1955 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1956 stats = NULL;
1957 GNUNET_notification_context_destroy (nc);
1958 nc = NULL;
1959 for (i=0;i<DEFAULT_FISHEYE_DEPTH;i++)
1960 {
1961 GNUNET_array_grow (consensi[i].targets,
1962 consensi[i].array_length,
1963 0);
1964 }
1965 if (NULL != rr_task)
1966 {
1967 GNUNET_SCHEDULER_cancel (rr_task);
1968 rr_task = NULL;
1969 }
1970}
1971
1972
1973/**
1974 * Notify newly connected client about an existing route.
1975 *
1976 * @param cls the `struct GNUNET_SERVICE_Client *`
1977 * @param key peer identity
1978 * @param value the `struct Route *`
1979 * @return #GNUNET_OK (continue to iterate)
1980 */
1981static int
1982notify_client_about_route (void *cls,
1983 const struct GNUNET_PeerIdentity *key,
1984 void *value)
1985{
1986 struct GNUNET_SERVICE_Client *client = cls;
1987 struct Route *route = value;
1988 struct GNUNET_MQ_Envelope *env;
1989 struct GNUNET_DV_ConnectMessage *cm;
1990
1991 env = GNUNET_MQ_msg (cm,
1992 GNUNET_MESSAGE_TYPE_DV_CONNECT);
1993 cm->distance = htonl (route->target.distance);
1994 cm->peer = route->target.peer;
1995 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
1996 env);
1997 return GNUNET_OK;
1998}
1999
2000
2001/**
2002 * Handle START-message. This is the first message sent to us
2003 * by the client (can only be one!).
2004 *
2005 * @param cls closure (always NULL)
2006 * @param client identification of the client
2007 * @param message the actual message
2008 */
2009static void
2010handle_start (void *cls,
2011 const struct GNUNET_MessageHeader *message)
2012{
2013 struct GNUNET_SERVICE_Client *client = cls;
2014
2015 GNUNET_notification_context_add (nc,
2016 GNUNET_SERVICE_client_get_mq (client));
2017 GNUNET_SERVICE_client_continue (client);
2018 GNUNET_CONTAINER_multipeermap_iterate (all_routes,
2019 &notify_client_about_route,
2020 client);
2021}
2022
2023
2024/**
2025 * Called on core init.
2026 *
2027 * @param cls unused
2028 * @param identity this peer's identity
2029 */
2030static void
2031core_init (void *cls,
2032 const struct GNUNET_PeerIdentity *identity)
2033{
2034 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2035 "I am peer: %s\n",
2036 GNUNET_i2s (identity));
2037 my_identity = *identity;
2038}
2039
2040
2041/**
2042 * Process dv requests.
2043 *
2044 * @param cls closure
2045 * @param c configuration to use
2046 * @param service the initialized service
2047 */
2048static void
2049run (void *cls,
2050 const struct GNUNET_CONFIGURATION_Handle *c,
2051 struct GNUNET_SERVICE_Handle *service)
2052{
2053 struct GNUNET_MQ_MessageHandler core_handlers[] = {
2054 GNUNET_MQ_hd_var_size (dv_route_message,
2055 GNUNET_MESSAGE_TYPE_DV_ROUTE,
2056 struct RouteMessage,
2057 NULL),
2058 GNUNET_MQ_handler_end ()
2059 };
2060 in_shutdown = GNUNET_NO;
2061 cfg = c;
2062 direct_neighbors = GNUNET_CONTAINER_multipeermap_create (128,
2063 GNUNET_NO);
2064 all_routes = GNUNET_CONTAINER_multipeermap_create (65536,
2065 GNUNET_NO);
2066 core_api = GNUNET_CORE_connect (cfg,
2067 NULL,
2068 &core_init,
2069 &handle_core_connect,
2070 &handle_core_disconnect,
2071 core_handlers);
2072
2073 if (NULL == core_api)
2074 return;
2075 ats = GNUNET_ATS_performance_init (cfg,
2076 &handle_ats_update,
2077 NULL);
2078 if (NULL == ats)
2079 {
2080 GNUNET_CORE_disconnect (core_api);
2081 core_api = NULL;
2082 return;
2083 }
2084 nc = GNUNET_notification_context_create (MAX_QUEUE_SIZE_PLUGIN);
2085 stats = GNUNET_STATISTICS_create ("dv",
2086 cfg);
2087 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
2088 NULL);
2089}
2090
2091
2092/**
2093 * Callback called when a client connects to the service.
2094 *
2095 * @param cls closure for the service
2096 * @param c the new client that connected to the service
2097 * @param mq the message queue used to send messages to the client
2098 * @return @a c
2099 */
2100static void *
2101client_connect_cb (void *cls,
2102 struct GNUNET_SERVICE_Client *c,
2103 struct GNUNET_MQ_Handle *mq)
2104{
2105 return c;
2106}
2107
2108
2109/**
2110 * Callback called when a client disconnected from the service
2111 *
2112 * @param cls closure for the service
2113 * @param c the client that disconnected
2114 * @param internal_cls should be equal to @a c
2115 */
2116static void
2117client_disconnect_cb (void *cls,
2118 struct GNUNET_SERVICE_Client *c,
2119 void *internal_cls)
2120{
2121 GNUNET_assert (c == internal_cls);
2122}
2123
2124
2125/**
2126 * Define "main" method using service macro.
2127 */
2128GNUNET_SERVICE_MAIN
2129("dv",
2130 GNUNET_SERVICE_OPTION_NONE,
2131 &run,
2132 &client_connect_cb,
2133 &client_disconnect_cb,
2134 NULL,
2135 GNUNET_MQ_hd_fixed_size (start,
2136 GNUNET_MESSAGE_TYPE_DV_START,
2137 struct GNUNET_MessageHeader,
2138 NULL),
2139 GNUNET_MQ_hd_var_size (dv_send_message,
2140 GNUNET_MESSAGE_TYPE_DV_SEND,
2141 struct GNUNET_DV_SendMessage,
2142 NULL),
2143 GNUNET_MQ_handler_end ());
2144
2145
2146/* end of gnunet-service-dv.c */
diff --git a/src/dv/plugin_transport_dv.c b/src/dv/plugin_transport_dv.c
deleted file mode 100644
index a99c170d7..000000000
--- a/src/dv/plugin_transport_dv.c
+++ /dev/null
@@ -1,910 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2002--2014 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 dv/plugin_transport_dv.c
23 * @brief DV transport service, takes incoming DV requests and deals with
24 * the DV service
25 * @author Nathan Evans
26 * @author Christian Grothoff
27 */
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_protocols.h"
31#include "gnunet_statistics_service.h"
32#include "gnunet_dv_service.h"
33#include "gnunet_transport_service.h"
34#include "gnunet_transport_plugin.h"
35#include "dv.h"
36
37
38#define LOG(kind,...) GNUNET_log_from (kind, "transport-dv",__VA_ARGS__)
39
40
41/**
42 * Encapsulation of all of the state of the plugin.
43 */
44struct Plugin;
45
46
47/**
48 * Session handle for connections.
49 */
50struct GNUNET_ATS_Session
51{
52 /**
53 * Pointer to the global plugin struct.
54 */
55 struct Plugin *plugin;
56
57 /**
58 * Address we use for the other peer.
59 */
60 struct GNUNET_HELLO_Address *address;
61
62 /**
63 * To whom are we talking to.
64 */
65 struct GNUNET_PeerIdentity sender;
66
67 /**
68 * Number of bytes waiting for transmission to this peer.
69 * FIXME: not set yet.
70 */
71 unsigned long long bytes_in_queue;
72
73 /**
74 * Number of messages waiting for transmission to this peer.
75 * FIXME: not set yet.
76 */
77 unsigned int msgs_in_queue;
78
79 /**
80 * Current distance to the given peer.
81 */
82 uint32_t distance;
83
84 /**
85 * Current network the next hop peer is located in
86 */
87 enum GNUNET_NetworkType network;
88
89 /**
90 * Does the transport service know about this session (and we thus
91 * need to call `session_end` when it is released?)
92 */
93 int active;
94
95};
96
97
98/**
99 * Encapsulation of all of the state of the plugin.
100 */
101struct Plugin
102{
103 /**
104 * Our environment.
105 */
106 struct GNUNET_TRANSPORT_PluginEnvironment *env;
107
108 /**
109 * Hash map of sessions (active and inactive).
110 */
111 struct GNUNET_CONTAINER_MultiPeerMap *sessions;
112
113 /**
114 * Copy of the handler array where the closures are
115 * set to this struct's instance.
116 */
117 struct GNUNET_SERVER_MessageHandler *handlers;
118
119 /**
120 * Handle to the DV service
121 */
122 struct GNUNET_DV_ServiceHandle *dvh;
123
124 /**
125 * Tokenizer for boxed messages.
126 */
127 struct GNUNET_SERVER_MessageStreamTokenizer *mst;
128
129 /**
130 * Function to call about session status changes.
131 */
132 GNUNET_TRANSPORT_SessionInfoCallback sic;
133
134 /**
135 * Closure for @e sic.
136 */
137 void *sic_cls;
138};
139
140
141/**
142 * If a session monitor is attached, notify it about the new
143 * session state.
144 *
145 * @param plugin our plugin
146 * @param session session that changed state
147 * @param state new state of the session
148 */
149static void
150notify_session_monitor (struct Plugin *plugin,
151 struct GNUNET_ATS_Session *session,
152 enum GNUNET_TRANSPORT_SessionState state)
153{
154 struct GNUNET_TRANSPORT_SessionInfo info;
155
156 if (NULL == plugin->sic)
157 return;
158 memset (&info, 0, sizeof (info));
159 info.state = state;
160 info.is_inbound = GNUNET_SYSERR; /* hard to say */
161 info.num_msg_pending = session->msgs_in_queue;
162 info.num_bytes_pending = session->bytes_in_queue;
163 /* info.receive_delay remains zero as this is not supported by DV
164 (cannot selectively not receive from 'core') */
165 info.session_timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
166 info.address = session->address;
167 plugin->sic (plugin->sic_cls,
168 session,
169 &info);
170}
171
172
173/**
174 * Notify transport service about the change in distance.
175 *
176 * @param session session where the distance changed
177 */
178static void
179notify_distance_change (struct GNUNET_ATS_Session *session)
180{
181 struct Plugin *plugin = session->plugin;
182
183 if (GNUNET_YES != session->active)
184 return;
185 plugin->env->update_address_distance (plugin->env->cls,
186 session->address,
187 session->distance);
188}
189
190
191/**
192 * Function called by MST on each message from the box.
193 *
194 * @param cls closure with the `struct Plugin *`
195 * @param client identification of the client (with the 'struct GNUNET_ATS_Session')
196 * @param message the actual message
197 * @return #GNUNET_OK on success
198 */
199static int
200unbox_cb (void *cls,
201 void *client,
202 const struct GNUNET_MessageHeader *message)
203{
204 struct Plugin *plugin = cls;
205 struct GNUNET_ATS_Session *session = client;
206
207 session->active = GNUNET_YES;
208 LOG (GNUNET_ERROR_TYPE_DEBUG,
209 "Delivering message of type %u with %u bytes from peer `%s'\n",
210 ntohs (message->type),
211 ntohs (message->size),
212 GNUNET_i2s (&session->sender));
213 plugin->env->receive (plugin->env->cls,
214 session->address,
215 session,
216 message);
217 plugin->env->update_address_distance (plugin->env->cls,
218 session->address,
219 session->distance);
220 return GNUNET_OK;
221}
222
223
224/**
225 * Handler for messages received from the DV service.
226 *
227 * @param cls closure with the plugin
228 * @param sender sender of the message
229 * @param distance how far did the message travel
230 * @param msg actual message payload
231 */
232static void
233handle_dv_message_received (void *cls,
234 const struct GNUNET_PeerIdentity *sender,
235 uint32_t distance,
236 const struct GNUNET_MessageHeader *msg)
237{
238 struct Plugin *plugin = cls;
239 struct GNUNET_ATS_Session *session;
240
241 LOG (GNUNET_ERROR_TYPE_DEBUG,
242 "Received DV_MESSAGE_RECEIVED message for peer `%s': new distance %u\n",
243 GNUNET_i2s (sender),
244 distance);
245 session = GNUNET_CONTAINER_multipeermap_get (plugin->sessions,
246 sender);
247 if (NULL == session)
248 {
249 GNUNET_break (0);
250 return;
251 }
252 if (GNUNET_MESSAGE_TYPE_DV_BOX == ntohs (msg->type))
253 {
254 /* need to unbox using MST */
255 LOG (GNUNET_ERROR_TYPE_DEBUG,
256 "Unboxing DV message using MST\n");
257 GNUNET_SERVER_mst_receive (plugin->mst,
258 session,
259 (const char *) &msg[1],
260 ntohs (msg->size) - sizeof (struct GNUNET_MessageHeader),
261 GNUNET_YES,
262 GNUNET_NO);
263 return;
264 }
265 session->active = GNUNET_YES;
266 LOG (GNUNET_ERROR_TYPE_DEBUG,
267 "Delivering message of type %u with %u bytes from peer `%s'\n",
268 ntohs (msg->type),
269 ntohs (msg->size),
270 GNUNET_i2s (sender));
271 plugin->env->receive (plugin->env->cls,
272 session->address,
273 session,
274 msg);
275 plugin->env->update_address_distance (plugin->env->cls,
276 session->address,
277 session->distance);
278}
279
280
281/**
282 * Function called if DV starts to be able to talk to a peer.
283 *
284 * @param cls closure with `struct Plugin *`
285 * @param peer newly connected peer
286 * @param distance distance to the peer
287 * @param network the network the next hop is located in
288 */
289static void
290handle_dv_connect (void *cls,
291 const struct GNUNET_PeerIdentity *peer,
292 uint32_t distance,
293 enum GNUNET_NetworkType network)
294{
295 struct Plugin *plugin = cls;
296 struct GNUNET_ATS_Session *session;
297
298 GNUNET_break (GNUNET_NT_UNSPECIFIED != network);
299 /**
300 * This requires transport plugin to be linked to libgnunetats.
301 * If you remove it, also remove libgnunetats linkage from Makefile.am
302 */
303 LOG (GNUNET_ERROR_TYPE_DEBUG,
304 "Received DV_CONNECT message for peer `%s' with next hop in network %s\n",
305 GNUNET_i2s (peer),
306 GNUNET_NT_to_string (network));
307
308 session = GNUNET_CONTAINER_multipeermap_get (plugin->sessions,
309 peer);
310 if (NULL != session)
311 {
312 GNUNET_break (0);
313 session->distance = distance;
314 notify_distance_change (session);
315 return; /* nothing to do */
316 }
317
318 session = GNUNET_new (struct GNUNET_ATS_Session);
319 session->address = GNUNET_HELLO_address_allocate (peer, "dv",
320 NULL, 0,
321 GNUNET_HELLO_ADDRESS_INFO_NONE);
322 session->sender = *peer;
323 session->plugin = plugin;
324 session->distance = distance;
325 session->network = network;
326 GNUNET_assert(GNUNET_YES ==
327 GNUNET_CONTAINER_multipeermap_put (plugin->sessions,
328 &session->sender, session,
329 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
330
331 LOG (GNUNET_ERROR_TYPE_DEBUG,
332 "Creating new DV session %p for peer `%s' at distance %u\n",
333 session,
334 GNUNET_i2s (peer),
335 distance);
336
337 session->active = GNUNET_YES;
338 plugin->env->session_start (plugin->env->cls,
339 session->address,
340 session,
341 network);
342 plugin->env->update_address_distance (plugin->env->cls,
343 session->address,
344 session->distance);
345
346 notify_session_monitor (session->plugin,
347 session,
348 GNUNET_TRANSPORT_SS_UP);
349}
350
351
352/**
353 * Function called if DV distance to a peer is changed.
354 *
355 * @param cls closure with `struct Plugin *`
356 * @param peer connected peer
357 * @param distance new distance to the peer
358 * @param network network type used for the connection
359 */
360static void
361handle_dv_distance_changed (void *cls,
362 const struct GNUNET_PeerIdentity *peer,
363 uint32_t distance,
364 enum GNUNET_NetworkType network)
365{
366 struct Plugin *plugin = cls;
367 struct GNUNET_ATS_Session *session;
368
369 GNUNET_break (GNUNET_NT_UNSPECIFIED != network);
370 LOG (GNUNET_ERROR_TYPE_DEBUG,
371 "Received `%s' message for peer `%s': new distance %u\n",
372 "DV_DISTANCE_CHANGED",
373 GNUNET_i2s (peer),
374 distance);
375 session = GNUNET_CONTAINER_multipeermap_get (plugin->sessions,
376 peer);
377 if (NULL == session)
378 {
379 GNUNET_break (0);
380 handle_dv_connect (plugin, peer, distance, network);
381 return;
382 }
383 session->distance = distance;
384 notify_distance_change (session);
385}
386
387
388/**
389 * Release session object and clean up associated resources.
390 *
391 * @param session session to clean up
392 */
393static void
394free_session (struct GNUNET_ATS_Session *session)
395{
396 struct Plugin *plugin = session->plugin;
397
398 GNUNET_assert (GNUNET_YES ==
399 GNUNET_CONTAINER_multipeermap_remove (plugin->sessions,
400 &session->sender,
401 session));
402
403 LOG (GNUNET_ERROR_TYPE_DEBUG,
404 "Freeing session %p for peer `%s'\n",
405 session,
406 GNUNET_i2s (&session->sender));
407 if (GNUNET_YES == session->active)
408 {
409 notify_session_monitor (session->plugin,
410 session,
411 GNUNET_TRANSPORT_SS_DONE);
412 plugin->env->session_end (plugin->env->cls,
413 session->address,
414 session);
415 session->active = GNUNET_NO;
416 }
417 GNUNET_HELLO_address_free (session->address);
418 GNUNET_free (session);
419}
420
421
422/**
423 * Function called if DV is no longer able to talk to a peer.
424 *
425 * @param cls closure with `struct Plugin *`
426 * @param peer peer that disconnected
427 */
428static void
429handle_dv_disconnect (void *cls,
430 const struct GNUNET_PeerIdentity *peer)
431{
432 struct Plugin *plugin = cls;
433 struct GNUNET_ATS_Session *session;
434
435 LOG (GNUNET_ERROR_TYPE_DEBUG,
436 "Received `%s' message for peer `%s'\n",
437 "DV_DISCONNECT",
438 GNUNET_i2s (peer));
439 session = GNUNET_CONTAINER_multipeermap_get (plugin->sessions,
440 peer);
441 if (NULL == session)
442 return; /* nothing to do */
443 free_session (session);
444}
445
446
447/**
448 * Function that can be used by the transport service to transmit
449 * a message using the plugin.
450 *
451 * @param cls closure
452 * @param session the session used
453 * @param priority how important is the message
454 * @param msgbuf the message to transmit
455 * @param msgbuf_size number of bytes in 'msgbuf'
456 * @param timeout when should we time out
457 * @param cont continuation to call once the message has
458 * been transmitted (or if the transport is ready
459 * for the next transmission call; or if the
460 * peer disconnected...)
461 * @param cont_cls closure for @a cont
462 * @return number of bytes used (on the physical network, with overheads);
463 * -1 on hard errors (i.e. address invalid); 0 is a legal value
464 * and does NOT mean that the message was not transmitted (DV)
465 */
466static ssize_t
467dv_plugin_send (void *cls,
468 struct GNUNET_ATS_Session *session,
469 const char *msgbuf,
470 size_t msgbuf_size,
471 unsigned int priority,
472 struct GNUNET_TIME_Relative timeout,
473 GNUNET_TRANSPORT_TransmitContinuation cont,
474 void *cont_cls)
475{
476 struct Plugin *plugin = cls;
477 const struct GNUNET_MessageHeader *msg;
478 struct GNUNET_MessageHeader *box;
479
480 box = NULL;
481 msg = (const struct GNUNET_MessageHeader *) msgbuf;
482 if (ntohs (msg->size) != msgbuf_size)
483 {
484 /* need to box */
485 LOG (GNUNET_ERROR_TYPE_DEBUG,
486 "Boxing DV message\n");
487 box = GNUNET_malloc (sizeof (struct GNUNET_MessageHeader) + msgbuf_size);
488 box->type = htons (GNUNET_MESSAGE_TYPE_DV_BOX);
489 box->size = htons (sizeof (struct GNUNET_MessageHeader) + msgbuf_size);
490 GNUNET_memcpy (&box[1], msgbuf, msgbuf_size);
491 msg = box;
492 }
493 GNUNET_DV_send (plugin->dvh,
494 &session->sender,
495 msg);
496 cont (cont_cls,
497 &session->sender,
498 GNUNET_OK,
499 msgbuf_size, 0);
500 GNUNET_free_non_null (box);
501 return 0; /* DV */
502}
503
504
505/**
506 * Function that can be used to force the plugin to disconnect
507 * from the given peer and cancel all previous transmissions
508 * (and their continuations).
509 *
510 * @param cls closure with the `struct Plugin *`
511 * @param target peer from which to disconnect
512 */
513static void
514dv_plugin_disconnect_peer (void *cls,
515 const struct GNUNET_PeerIdentity *target)
516{
517 struct Plugin *plugin = cls;
518 struct GNUNET_ATS_Session *session;
519
520 session = GNUNET_CONTAINER_multipeermap_get (plugin->sessions,
521 target);
522 if (NULL == session)
523 return; /* nothing to do */
524 session->active = GNUNET_NO;
525}
526
527
528/**
529 * Function that can be used to force the plugin to disconnect
530 * from the given peer and cancel all previous transmissions
531 * (and their continuations).
532 *
533 * @param cls closure with the `struct Plugin *`
534 * @param session which session to disconnect
535 * @return #GNUNET_OK
536 */
537static int
538dv_plugin_disconnect_session (void *cls,
539 struct GNUNET_ATS_Session *session)
540{
541 session->active = GNUNET_NO;
542 return GNUNET_OK;
543}
544
545
546/**
547 * Convert the transports address to a nice, human-readable
548 * format.
549 *
550 * @param cls closure
551 * @param type name of the transport that generated the address
552 * @param addr one of the addresses of the host, NULL for the last address
553 * the specific address format depends on the transport
554 * @param addrlen length of the address
555 * @param numeric should (IP) addresses be displayed in numeric form?
556 * @param timeout after how long should we give up?
557 * @param asc function to call on each string
558 * @param asc_cls closure for @a asc
559 */
560static void
561dv_plugin_address_pretty_printer (void *cls,
562 const char *type,
563 const void *addr,
564 size_t addrlen,
565 int numeric,
566 struct GNUNET_TIME_Relative timeout,
567 GNUNET_TRANSPORT_AddressStringCallback asc,
568 void *asc_cls)
569{
570 if ( (0 == addrlen) &&
571 (0 == strcmp (type, "dv")) )
572 asc (asc_cls,
573 "dv",
574 GNUNET_OK);
575 else
576 asc (asc_cls,
577 NULL,
578 GNUNET_SYSERR);
579 asc (asc_cls,
580 NULL,
581 GNUNET_OK);
582}
583
584
585/**
586 * Convert the DV address to a pretty string.
587 *
588 * @param cls closure
589 * @param addr the (hopefully) DV address
590 * @param addrlen the length of the @a addr
591 * @return string representing the DV address
592 */
593static const char *
594dv_plugin_address_to_string (void *cls,
595 const void *addr,
596 size_t addrlen)
597{
598 if (0 != addrlen)
599 {
600 GNUNET_break (0); /* malformed */
601 return NULL;
602 }
603 return "dv";
604}
605
606
607/**
608 * Another peer has suggested an address for this peer and transport
609 * plugin. Check that this could be a valid address. This function
610 * is not expected to 'validate' the address in the sense of trying to
611 * connect to it but simply to see if the binary format is technically
612 * legal for establishing a connection to this peer (and make sure that
613 * the address really corresponds to our network connection/settings
614 * and not some potential man-in-the-middle).
615 *
616 * @param cls closure
617 * @param addr pointer to the address
618 * @param addrlen length of @a addr
619 * @return #GNUNET_OK if this is a plausible address for this peer
620 * and transport, #GNUNET_SYSERR if not
621 *
622 */
623static int
624dv_plugin_check_address (void *cls,
625 const void *addr,
626 size_t addrlen)
627{
628 if (0 != addrlen)
629 return GNUNET_SYSERR;
630 return GNUNET_OK;
631}
632
633
634/**
635 * Create a new session to transmit data to the target
636 * This session will used to send data to this peer and the plugin will
637 * notify us by calling the env->session_end function
638 *
639 * @param cls the plugin
640 * @param address the address
641 * @return the session if the address is valid, NULL otherwise
642 */
643static struct GNUNET_ATS_Session *
644dv_get_session (void *cls,
645 const struct GNUNET_HELLO_Address *address)
646{
647 struct Plugin *plugin = cls;
648 struct GNUNET_ATS_Session *session;
649
650 if (0 != address->address_length)
651 return NULL;
652 session = GNUNET_CONTAINER_multipeermap_get (plugin->sessions,
653 &address->peer);
654 if (NULL == session)
655 return NULL; /* not valid right now */
656 session->active = GNUNET_YES;
657 return session;
658}
659
660
661/**
662 * Function called to convert a string address to
663 * a binary address.
664 *
665 * @param cls closure ('struct Plugin*')
666 * @param addr string address
667 * @param addrlen length of the @a addr including \0 termination
668 * @param buf location to store the buffer
669 * If the function returns #GNUNET_SYSERR, its contents are undefined.
670 * @param added length of created address
671 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
672 */
673static int
674dv_plugin_string_to_address (void *cls,
675 const char *addr,
676 uint16_t addrlen,
677 void **buf,
678 size_t *added)
679{
680 if ( (addrlen == 3) &&
681 (0 == strcmp ("dv", addr)) )
682 {
683 *added = 0;
684 return GNUNET_OK;
685 }
686 return GNUNET_SYSERR;
687}
688
689
690/**
691 * Function that will be called whenever the transport service wants to
692 * notify the plugin that a session is still active and in use and
693 * therefore the session timeout for this session has to be updated
694 *
695 * @param cls closure (`struct Plugin *`)
696 * @param peer which peer was the session for
697 * @param session which session is being updated
698 */
699static void
700dv_plugin_update_session_timeout (void *cls,
701 const struct GNUNET_PeerIdentity *peer,
702 struct GNUNET_ATS_Session *session)
703{
704 /* DV currently doesn't time out like "normal" plugins,
705 so it should be safe to do nothing, right?
706 (or should we add an internal timeout?) */
707}
708
709
710/**
711 * Function to obtain the network type for a session
712 * FIXME: we should probably look at the network type
713 * used by the next hop here. Or find some other way
714 * to properly allow ATS-DV resource allocation.
715 *
716 * @param cls closure (`struct Plugin *`)
717 * @param session the session
718 * @return the network type
719 */
720static enum GNUNET_NetworkType
721dv_get_network (void *cls,
722 struct GNUNET_ATS_Session *session)
723{
724 GNUNET_assert (NULL != session);
725 return session->network;
726}
727
728
729/**
730 * Function obtain the network type for an address.
731 *
732 * @param cls closure (`struct Plugin *`)
733 * @param address the address
734 * @return the network type
735 */
736static enum GNUNET_NetworkType
737dv_plugin_get_network_for_address (void *cls,
738 const struct GNUNET_HELLO_Address *address)
739{
740 return GNUNET_NT_WAN; /* FOR NOW */
741}
742
743
744/**
745 * Function that is called to get the keepalive factor.
746 * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
747 * calculate the interval between keepalive packets.
748 *
749 * @param cls closure with the `struct Plugin`
750 * @return keepalive factor
751 */
752static unsigned int
753dv_plugin_query_keepalive_factor (void *cls)
754{
755 return 3;
756}
757
758
759/**
760 * Return information about the given session to the
761 * monitor callback.
762 *
763 * @param cls the `struct Plugin` with the monitor callback (`sic`)
764 * @param peer peer we send information about
765 * @param value our `struct GNUNET_ATS_Session` to send information about
766 * @return #GNUNET_OK (continue to iterate)
767 */
768static int
769send_session_info_iter (void *cls,
770 const struct GNUNET_PeerIdentity *peer,
771 void *value)
772{
773 struct Plugin *plugin = cls;
774 struct GNUNET_ATS_Session *session = value;
775
776 if (GNUNET_YES != session->active)
777 return GNUNET_OK;
778 notify_session_monitor (plugin,
779 session,
780 GNUNET_TRANSPORT_SS_UP);
781 return GNUNET_OK;
782}
783
784
785/**
786 * Begin monitoring sessions of a plugin. There can only
787 * be one active monitor per plugin (i.e. if there are
788 * multiple monitors, the transport service needs to
789 * multiplex the generated events over all of them).
790 *
791 * @param cls closure of the plugin
792 * @param sic callback to invoke, NULL to disable monitor;
793 * plugin will being by iterating over all active
794 * sessions immediately and then enter monitor mode
795 * @param sic_cls closure for @a sic
796 */
797static void
798dv_plugin_setup_monitor (void *cls,
799 GNUNET_TRANSPORT_SessionInfoCallback sic,
800 void *sic_cls)
801{
802 struct Plugin *plugin = cls;
803
804 plugin->sic = sic;
805 plugin->sic_cls = sic_cls;
806 if (NULL != sic)
807 {
808 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
809 &send_session_info_iter,
810 plugin);
811 /* signal end of first iteration */
812 sic (sic_cls, NULL, NULL);
813 }
814}
815
816
817/**
818 * Entry point for the plugin.
819 *
820 * @param cls closure with the plugin environment
821 * @return plugin API
822 */
823void *
824libgnunet_plugin_transport_dv_init (void *cls)
825{
826 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
827 struct GNUNET_TRANSPORT_PluginFunctions *api;
828 struct Plugin *plugin;
829
830 plugin = GNUNET_new (struct Plugin);
831 plugin->env = env;
832 plugin->sessions = GNUNET_CONTAINER_multipeermap_create (1024 * 8, GNUNET_YES);
833 plugin->mst = GNUNET_SERVER_mst_create (&unbox_cb,
834 plugin);
835 plugin->dvh = GNUNET_DV_service_connect (env->cfg,
836 plugin,
837 &handle_dv_connect,
838 &handle_dv_distance_changed,
839 &handle_dv_disconnect,
840 &handle_dv_message_received);
841 if (NULL == plugin->dvh)
842 {
843 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessions);
844 GNUNET_SERVER_mst_destroy (plugin->mst);
845 GNUNET_free (plugin);
846 return NULL;
847 }
848 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
849 api->cls = plugin;
850 api->send = &dv_plugin_send;
851 api->disconnect_peer = &dv_plugin_disconnect_peer;
852 api->disconnect_session = &dv_plugin_disconnect_session;
853 api->address_pretty_printer = &dv_plugin_address_pretty_printer;
854 api->check_address = &dv_plugin_check_address;
855 api->address_to_string = &dv_plugin_address_to_string;
856 api->string_to_address = &dv_plugin_string_to_address;
857 api->query_keepalive_factor = &dv_plugin_query_keepalive_factor;
858 api->get_session = &dv_get_session;
859 api->get_network = &dv_get_network;
860 api->get_network_for_address = &dv_plugin_get_network_for_address;
861 api->update_session_timeout = &dv_plugin_update_session_timeout;
862 api->setup_monitor = &dv_plugin_setup_monitor;
863 return api;
864}
865
866
867/**
868 * Function called to free a session.
869 *
870 * @param cls NULL
871 * @param key unused
872 * @param value session to free
873 * @return #GNUNET_OK (continue to iterate)
874 */
875static int
876free_session_iterator (void *cls,
877 const struct GNUNET_PeerIdentity *key,
878 void *value)
879{
880 struct GNUNET_ATS_Session *session = value;
881
882 free_session (session);
883 return GNUNET_OK;
884}
885
886
887/**
888 * Exit point from the plugin.
889 *
890 * @param cls plugin API
891 * @return NULL
892 */
893void *
894libgnunet_plugin_transport_dv_done (void *cls)
895{
896 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
897 struct Plugin *plugin = api->cls;
898
899 GNUNET_DV_service_disconnect (plugin->dvh);
900 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
901 &free_session_iterator,
902 NULL);
903 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessions);
904 GNUNET_SERVER_mst_destroy (plugin->mst);
905 GNUNET_free (plugin);
906 GNUNET_free (api);
907 return NULL;
908}
909
910/* end of plugin_transport_dv.c */
diff --git a/src/dv/template_dv.conf b/src/dv/template_dv.conf
deleted file mode 100644
index d37154261..000000000
--- a/src/dv/template_dv.conf
+++ /dev/null
@@ -1,33 +0,0 @@
1# Peers:
2#
3# `G3FK2T8AMPJ0H556QXEYVTEW409BP3KHPCG99TV66V8NYAS1KEWG'
4# `6DEVS8Y51AT0TGNNHR7A75H47XXYJEFRZXX5RVQ9Q6S7Z49SYXT0'
5# `6YNBKM6TTK64FAG9DF0292AW5JA9CCAC04JTY0HF8XHP635HPBBG'
6# `DK5WZKKDHH06BH1H0DE0Z8CPBTG9AD8P85SF02WW3285AT3V0V50'
7#
8
9[testbed]
10OVERLAY_TOPOLOGY = CLIQUE
11SETUP_TIMEOUT = 3 m
12OPERATION_TIMEOUT = 30 s
13CACHE_SIZE = 0
14
15[transport-blacklist-G3FK2T8AMPJ0H556QXEYVTEW409BP3KHPCG99TV66V8NYAS1KEWG]
166DEVS8Y51AT0TGNNHR7A75H47XXYJEFRZXX5RVQ9Q6S7Z49SYXT0 = tcp
17
18[transport-blacklist-6DEVS8Y51AT0TGNNHR7A75H47XXYJEFRZXX5RVQ9Q6S7Z49SYXT0]
19G3FK2T8AMPJ0H556QXEYVTEW409BP3KHPCG99TV66V8NYAS1KEWG = tcp
20
21[transport-blacklist-6YNBKM6TTK64FAG9DF0292AW5JA9CCAC04JTY0HF8XHP635HPBBG]
22
23[transport-blacklist-DK5WZKKDHH06BH1H0DE0Z8CPBTG9AD8P85SF02WW3285AT3V0V50]
24
25[PATHS]
26GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-dv-testing/
27
28[peerinfo]
29USE_INCLUDED_HELLOS = NO
30
31[nat]
32RETURN_LOCAL_ADDRESSES = YES
33
diff --git a/src/dv/test_transport_blacklist.c b/src/dv/test_transport_blacklist.c
deleted file mode 100644
index 4fc9b4908..000000000
--- a/src/dv/test_transport_blacklist.c
+++ /dev/null
@@ -1,69 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 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 dv/test_transport_blacklist.c
22 * @brief base testcase for testing blacklist
23 */
24#include "platform.h"
25#include "gnunet_core_service.h"
26#include "gnunet_testbed_service.h"
27
28/**
29 * Return value from main, set to 0 on success.
30 */
31static int ok;
32
33
34static void
35test_connection (void *cls,
36 struct GNUNET_TESTBED_RunHandle *h,
37 unsigned int num_peers,
38 struct GNUNET_TESTBED_Peer **peers,
39 unsigned int links_succeeded,
40 unsigned int links_failed)
41{
42 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Links successful %u / %u failed\n", links_succeeded, links_failed);
43 if ( (4 == num_peers) && (0 == links_failed) )
44 {
45 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
46 "Testbed connect peers despite blacklist!\n");
47 ok = 1;
48 }
49 else
50 {
51 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
52 "Note that getting a message about a timeout during setup is expected for this test.\n");
53 }
54 GNUNET_SCHEDULER_shutdown ();
55}
56
57
58int
59main (int argc, char *argv[])
60{
61 (void) GNUNET_TESTBED_test_run ("test-transport-blacklist",
62 "test_transport_blacklist_data.conf",
63 4,
64 0, NULL, NULL,
65 &test_connection, NULL);
66 return ok;
67}
68
69/* end of test_transport_blacklist.c */
diff --git a/src/dv/test_transport_blacklist_data.conf b/src/dv/test_transport_blacklist_data.conf
deleted file mode 100644
index ea55a196b..000000000
--- a/src/dv/test_transport_blacklist_data.conf
+++ /dev/null
@@ -1,5 +0,0 @@
1@INLINE@ template_dv.conf
2
3[transport]
4PORT = 52565
5PLUGINS = tcp
diff --git a/src/dv/test_transport_dv.c b/src/dv/test_transport_dv.c
deleted file mode 100644
index 03b6087d5..000000000
--- a/src/dv/test_transport_dv.c
+++ /dev/null
@@ -1,131 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 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 dv/test_transport_dv.c
22 * @brief base testcase for testing distance vector transport
23 */
24#include "platform.h"
25#include "gnunet_core_service.h"
26#include "gnunet_testbed_service.h"
27
28/**
29 * Return value from main, set to 0 on success.
30 */
31static int ok;
32
33struct GNUNET_TESTBED_Operation *topology_op;
34
35static struct GNUNET_SCHEDULER_Task * shutdown_task;
36
37
38static void
39do_shutdown (void *cls)
40{
41 shutdown_task = NULL;
42 if (NULL != topology_op)
43 {
44 GNUNET_TESTBED_operation_done (topology_op);
45 topology_op = NULL;
46 }
47}
48
49
50static void
51topology_completed (void *cls,
52 unsigned int nsuccess,
53 unsigned int nfailures)
54{
55 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
56 "Links successful %u / %u failed\n",
57 nsuccess,
58 nfailures);
59 GNUNET_TESTBED_operation_done (topology_op);
60 topology_op = NULL;
61
62 if (nfailures > 0)
63 {
64 fprintf (stderr,
65 "Error: links successful %u but %u failed\n",
66 nsuccess,
67 nfailures);
68 ok = 1;
69 }
70 else
71 ok = 0;
72
73 GNUNET_SCHEDULER_shutdown ();
74}
75
76
77static void
78test_connection (void *cls,
79 struct GNUNET_TESTBED_RunHandle *h,
80 unsigned int num_peers,
81 struct GNUNET_TESTBED_Peer **peers,
82 unsigned int links_succeeded,
83 unsigned int links_failed)
84{
85 shutdown_task = GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
86 NULL);
87 if (4 != num_peers)
88 {
89 ok = 1;
90 fprintf (stderr,
91 "Only %u out of 4 peers were started ...\n",
92 num_peers);
93 }
94
95 if (0 != links_failed)
96 {
97 /* All peers except DV peers are connected */
98 fprintf (stderr,
99 "Testbed failed to connect peers (%u links OK, %u links failed)\n",
100 links_succeeded,
101 links_failed);
102
103 topology_op = GNUNET_TESTBED_overlay_configure_topology
104 (NULL, num_peers, peers, NULL,
105 &topology_completed, NULL,
106 GNUNET_TESTBED_TOPOLOGY_CLIQUE,
107 GNUNET_TESTBED_TOPOLOGY_OPTION_END);
108 return;
109 }
110
111 ok = 1;
112 fprintf (stderr,
113 "Testbed connected peers, should not happen...\n");
114 GNUNET_SCHEDULER_shutdown ();
115}
116
117
118int
119main (int argc, char *argv[])
120{
121 ok = 1;
122 /* Connecting initial topology */
123 (void) GNUNET_TESTBED_test_run ("test-transport-dv",
124 "test_transport_dv_data.conf",
125 4,
126 0, NULL, NULL,
127 &test_connection, NULL);
128 return ok;
129}
130
131/* end of test_transport_dv.c */
diff --git a/src/dv/test_transport_dv_data.conf b/src/dv/test_transport_dv_data.conf
deleted file mode 100644
index a21fba8a7..000000000
--- a/src/dv/test_transport_dv_data.conf
+++ /dev/null
@@ -1,19 +0,0 @@
1@INLINE@ template_dv.conf
2
3[transport]
4PORT = 52565
5PLUGINS = tcp dv
6#PREFIX = valgrind --leak-check=full --track-fds=yes --leak-resolution=high
7
8[dv]
9START_ON_DEMAND = YES
10# PREFIX = valgrind --leak-check=full --track-fds=yes --leak-resolution=high
11
12[set]
13START_ON_DEMAND = YES
14# PREFIX = valgrind --leak-check=full --track-fds=yes --leak-resolution=high
15
16[core]
17# PREFIX = valgrind --leak-check=full --track-fds=yes --leak-resolution=high
18
19
diff --git a/src/fs/Makefile.am b/src/fs/Makefile.am
index 33260a794..d452bbf3c 100644
--- a/src/fs/Makefile.am
+++ b/src/fs/Makefile.am
@@ -282,11 +282,6 @@ check_SCRIPTS += \
282endif 282endif
283endif 283endif
284 284
285if ENABLE_MONKEY
286 MONKEY = @MONKEYPREFIX@
287 AM_LDFLAGS = -no-install
288endif
289
290 285
291if ENABLE_TEST_RUN 286if ENABLE_TEST_RUN
292AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; $(MONKEY) 287AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; $(MONKEY)
diff --git a/src/fs/fs.conf.in b/src/fs/fs.conf.in
index 92bcf776d..1e4c5c268 100644
--- a/src/fs/fs.conf.in
+++ b/src/fs/fs.conf.in
@@ -11,6 +11,8 @@ BINARY = gnunet-service-fs
11ACCEPT_FROM = 127.0.0.1; 11ACCEPT_FROM = 127.0.0.1;
12ACCEPT_FROM6 = ::1; 12ACCEPT_FROM6 = ::1;
13 13
14# PREFIX = valgrind
15
14# Do we introduce artificial delays? (may improve anonymity) 16# Do we introduce artificial delays? (may improve anonymity)
15DELAY = YES 17DELAY = YES
16 18
diff --git a/src/fs/fs_dirmetascan.c b/src/fs/fs_dirmetascan.c
index 4a86a717f..115f99391 100644
--- a/src/fs/fs_dirmetascan.c
+++ b/src/fs/fs_dirmetascan.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -332,10 +332,7 @@ process_helper_msgs (void *cls,
332 break; 332 break;
333 } 333 }
334 if (NULL == ds->toplevel) 334 if (NULL == ds->toplevel)
335 {
336 GNUNET_break (0);
337 break; 335 break;
338 }
339 ds->progress_callback (ds->progress_callback_cls, 336 ds->progress_callback (ds->progress_callback_cls,
340 NULL, GNUNET_SYSERR, 337 NULL, GNUNET_SYSERR,
341 GNUNET_FS_DIRSCANNER_ALL_COUNTED); 338 GNUNET_FS_DIRSCANNER_ALL_COUNTED);
@@ -408,10 +405,7 @@ process_helper_msgs (void *cls,
408 break; 405 break;
409 } 406 }
410 if (NULL == ds->toplevel) 407 if (NULL == ds->toplevel)
411 {
412 GNUNET_break (0);
413 break; 408 break;
414 }
415 ds->stop_task = GNUNET_SCHEDULER_add_now (&finish_scan, 409 ds->stop_task = GNUNET_SCHEDULER_add_now (&finish_scan,
416 ds); 410 ds);
417 return GNUNET_OK; 411 return GNUNET_OK;
diff --git a/src/fs/fs_publish.c b/src/fs/fs_publish.c
index c7f3c4152..71ab1122c 100644
--- a/src/fs/fs_publish.c
+++ b/src/fs/fs_publish.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -716,17 +716,21 @@ handle_index_start_failed (void *cls,
716 struct GNUNET_FS_PublishContext *pc = cls; 716 struct GNUNET_FS_PublishContext *pc = cls;
717 struct GNUNET_FS_FileInformation *p; 717 struct GNUNET_FS_FileInformation *p;
718 const char *emsg = (const char *) &msg[1]; 718 const char *emsg = (const char *) &msg[1];
719 char *msgtxt;
719 720
720 GNUNET_MQ_destroy (pc->mq); 721 GNUNET_MQ_destroy (pc->mq);
721 pc->mq = NULL; 722 pc->mq = NULL;
722 p = pc->fi_pos; 723 p = pc->fi_pos;
723 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 724 GNUNET_asprintf (&msgtxt,
724 _("Can not index file `%s': %s. Will try to insert instead.\n"), 725 _("Can not index file `%s': %s.\n"),
725 p->filename, 726 p->filename,
726 gettext (emsg)); 727 gettext (emsg));
727 p->data.file.do_index = GNUNET_NO; 728 signal_publish_error (p,
729 pc,
730 msgtxt);
731 GNUNET_free (msgtxt);
728 GNUNET_FS_file_information_sync_ (p); 732 GNUNET_FS_file_information_sync_ (p);
729 publish_content (pc); 733 GNUNET_FS_publish_sync_ (pc);
730} 734}
731 735
732 736
diff --git a/src/fs/gnunet-publish.c b/src/fs/gnunet-publish.c
index a825795cb..eb8a7ed19 100644
--- a/src/fs/gnunet-publish.c
+++ b/src/fs/gnunet-publish.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -684,7 +684,7 @@ directory_scan_cb (void *cls,
684 case GNUNET_FS_DIRSCANNER_INTERNAL_ERROR: 684 case GNUNET_FS_DIRSCANNER_INTERNAL_ERROR:
685 FPRINTF (stdout, 685 FPRINTF (stdout,
686 "%s", 686 "%s",
687 _("Internal error scanning directory.\n")); 687 _("Error scanning directory.\n"));
688 ret = 1; 688 ret = 1;
689 GNUNET_SCHEDULER_shutdown (); 689 GNUNET_SCHEDULER_shutdown ();
690 break; 690 break;
diff --git a/src/fs/gnunet-search.c b/src/fs/gnunet-search.c
index 57d8eed5d..3995b1b5b 100644
--- a/src/fs/gnunet-search.c
+++ b/src/fs/gnunet-search.c
@@ -172,8 +172,11 @@ progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info)
172 is_directory = 172 is_directory =
173 GNUNET_FS_meta_data_test_for_directory (info->value.search. 173 GNUNET_FS_meta_data_test_for_directory (info->value.search.
174 specifics.result.meta); 174 specifics.result.meta);
175 if (filename != NULL) 175 if (NULL != filename)
176 { 176 {
177 while ( (filename[0] != '\0') &&
178 ('/' == filename[strlen(filename)-1]) )
179 filename[strlen(filename)-1] = '\0';
177 GNUNET_DISK_filename_canonicalize (filename); 180 GNUNET_DISK_filename_canonicalize (filename);
178 if (GNUNET_YES == is_directory) 181 if (GNUNET_YES == is_directory)
179 printf ("gnunet-download -o \"%s%s\" -R %s\n", filename, GNUNET_FS_DIRECTORY_EXT, uri); 182 printf ("gnunet-download -o \"%s%s\" -R %s\n", filename, GNUNET_FS_DIRECTORY_EXT, uri);
diff --git a/src/fs/gnunet-service-fs_cadet_client.c b/src/fs/gnunet-service-fs_cadet_client.c
index 61f73a50a..9ba250dfa 100644
--- a/src/fs/gnunet-service-fs_cadet_client.c
+++ b/src/fs/gnunet-service-fs_cadet_client.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -469,8 +469,11 @@ reset_cadet (struct CadetHandle *mh)
469 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 469 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
470 "Resetting cadet channel to %s\n", 470 "Resetting cadet channel to %s\n",
471 GNUNET_i2s (&mh->target)); 471 GNUNET_i2s (&mh->target));
472 GNUNET_CADET_channel_destroy (mh->channel); 472 if (NULL != mh->channel)
473 mh->channel = NULL; 473 {
474 GNUNET_CADET_channel_destroy (mh->channel);
475 mh->channel = NULL;
476 }
474 GNUNET_CONTAINER_multihashmap_iterate (mh->waiting_map, 477 GNUNET_CONTAINER_multihashmap_iterate (mh->waiting_map,
475 &move_to_pending, 478 &move_to_pending,
476 mh); 479 mh);
@@ -741,7 +744,17 @@ GSF_cadet_release_clients (void *cls,
741 "Timeout on cadet channel to %s\n", 744 "Timeout on cadet channel to %s\n",
742 GNUNET_i2s (&mh->target)); 745 GNUNET_i2s (&mh->target));
743 if (NULL != mh->channel) 746 if (NULL != mh->channel)
744 GNUNET_CADET_channel_destroy (mh->channel); 747 {
748 struct GNUNET_CADET_Channel *channel = mh->channel;
749
750 mh->channel = NULL;
751 GNUNET_CADET_channel_destroy (channel);
752 }
753 if (NULL != mh->reset_task)
754 {
755 GNUNET_SCHEDULER_cancel (mh->reset_task);
756 mh->reset_task = NULL;
757 }
745 return GNUNET_YES; 758 return GNUNET_YES;
746} 759}
747 760
diff --git a/src/fs/test_gnunet_fs_psd.py.in b/src/fs/test_gnunet_fs_psd.py.in
index 416ab5db3..d5a036c28 100755
--- a/src/fs/test_gnunet_fs_psd.py.in
+++ b/src/fs/test_gnunet_fs_psd.py.in
@@ -18,6 +18,7 @@
18# SPDX-License-Identifier: AGPL3.0-or-later 18# SPDX-License-Identifier: AGPL3.0-or-later
19# 19#
20# Testcase for file-sharing command-line tools (publish, search, download) 20# Testcase for file-sharing command-line tools (publish, search, download)
21from __future__ import print_function
21import sys 22import sys
22import os 23import os
23import subprocess 24import subprocess
diff --git a/src/gns/.gitignore b/src/gns/.gitignore
index 2b9a18f21..3bbb2eb3d 100644
--- a/src/gns/.gitignore
+++ b/src/gns/.gitignore
@@ -4,3 +4,9 @@ gnunet-dns2gns
4gnunet-gns 4gnunet-gns
5gnunet-gns-proxy 5gnunet-gns-proxy
6gnunet-gns-benchmark 6gnunet-gns-benchmark
7test_gns_proxy
8local.crt
9local.der
10local.key
11server.csr
12gnunet-gns-proxy-setup-ca
diff --git a/src/gns/Makefile.am b/src/gns/Makefile.am
index 1abc57d57..434d50f34 100644
--- a/src/gns/Makefile.am
+++ b/src/gns/Makefile.am
@@ -14,7 +14,8 @@ EXTRA_DIST = \
14 test_gns_simple_lookup.conf \ 14 test_gns_simple_lookup.conf \
15 gns-helper-service-w32.conf \ 15 gns-helper-service-w32.conf \
16 w32nsp.def \ 16 w32nsp.def \
17 gnunet-gns-proxy-setup-ca \ 17 openssl.cnf \
18 gnunet-gns-proxy-setup-ca.in \
18 zonefiles/J7POEUT41A8PBFS7KVVDRF88GBOU4HK8PSU5QKVLVE3R9T91E99G.zkey \ 19 zonefiles/J7POEUT41A8PBFS7KVVDRF88GBOU4HK8PSU5QKVLVE3R9T91E99G.zkey \
19 zonefiles/OEFL7A4VEF1B40QLEMTG5D8G1CN6EN16QUSG5R2DT71GRJN34LSG.zkey \ 20 zonefiles/OEFL7A4VEF1B40QLEMTG5D8G1CN6EN16QUSG5R2DT71GRJN34LSG.zkey \
20 zonefiles/test_zonekey \ 21 zonefiles/test_zonekey \
@@ -79,19 +80,30 @@ bin_PROGRAMS = \
79noinst_PROGRAMS = \ 80noinst_PROGRAMS = \
80 gnunet-gns-benchmark 81 gnunet-gns-benchmark
81 82
83pkgdata_DATA = \
84 openssl.cnf
85
82if HAVE_MHD 86if HAVE_MHD
83if LINUX 87if LINUX
84bin_PROGRAMS += gnunet-bcd 88bin_PROGRAMS += gnunet-bcd
85endif 89endif
86endif 90endif
87 91
88bin_SCRIPTS = gnunet-gns-proxy-setup-ca
89
90plugin_LTLIBRARIES = \ 92plugin_LTLIBRARIES = \
91 libgnunet_plugin_block_gns.la \ 93 libgnunet_plugin_block_gns.la \
92 libgnunet_plugin_gnsrecord_gns.la 94 libgnunet_plugin_gnsrecord_gns.la
93 95
94 96
97bin_SCRIPTS = \
98 gnunet-gns-proxy-setup-ca
99
100# See: https://www.gnu.org/software/automake/manual/html_node/Scripts.html#Scripts
101do_subst = sed -e 's,[@]pkgdatadir[@],$(pkgdatadir),g'
102
103gnunet-gns-proxy-setup-ca: gnunet-gns-proxy-setup-ca.in Makefile
104 $(do_subst) < $(srcdir)/gnunet-gns-proxy-setup-ca.in > gnunet-gns-proxy-setup-ca
105 chmod +x gnunet-gns-proxy-setup-ca
106
95libgnunet_plugin_gnsrecord_gns_la_SOURCES = \ 107libgnunet_plugin_gnsrecord_gns_la_SOURCES = \
96 plugin_gnsrecord_gns.c 108 plugin_gnsrecord_gns.c
97libgnunet_plugin_gnsrecord_gns_la_LIBADD = \ 109libgnunet_plugin_gnsrecord_gns_la_LIBADD = \
diff --git a/src/gns/gnunet-gns-proxy-setup-ca b/src/gns/gnunet-gns-proxy-setup-ca.in
index 7c1d58dc2..0a6fab18a 100644
--- a/src/gns/gnunet-gns-proxy-setup-ca
+++ b/src/gns/gnunet-gns-proxy-setup-ca.in
@@ -3,15 +3,13 @@
3# and install it (for both GNUnet and your browser). 3# and install it (for both GNUnet and your browser).
4# 4#
5 5
6# TODO: We should sed the real paths to the binaries involved here. 6OPENSSLCFG=@pkgdatadir@/openssl.cnf
7
8if ! which openssl > /dev/null 7if ! which openssl > /dev/null
9then 8then
10 echo "'openssl' command not found. Please install it." 9 echo "'openssl' command not found. Please install it."
11 exit 1 10 exit 1
12fi 11fi
13 12
14
15echo "Generating CA" 13echo "Generating CA"
16options='' 14options=''
17while getopts "c:" opt; do 15while getopts "c:" opt; do
@@ -36,7 +34,7 @@ GNSCANO=`mktemp /tmp/gnscakeynoencXXXXXX.pem`
36GNS_CA_CERT_PEM=`gnunet-config -s gns-proxy -o PROXY_CACERT -f $options` 34GNS_CA_CERT_PEM=`gnunet-config -s gns-proxy -o PROXY_CACERT -f $options`
37mkdir -p `dirname $GNS_CA_CERT_PEM` 35mkdir -p `dirname $GNS_CA_CERT_PEM`
38 36
39openssl req -new -x509 -days 3650 -extensions v3_ca -keyout $GNSCAKY -out $GNSCERT -subj "/C=ZZ/L=World/O=GNU/OU=GNUnet/CN=GNS Proxy CA/emailAddress=bounce@gnunet.org" -passout pass:"GNU Name System" 37openssl req -config $OPENSSLCFG -new -x509 -days 3650 -extensions v3_ca -keyout $GNSCAKY -out $GNSCERT -subj "/C=ZZ/L=World/O=GNU/OU=GNUnet/CN=GNS Proxy CA/emailAddress=bounce@gnunet.org" -passout pass:"GNU Name System"
40 38
41echo "Removing passphrase from key" 39echo "Removing passphrase from key"
42openssl rsa -passin pass:"GNU Name System" -in $GNSCAKY -out $GNSCANO 40openssl rsa -passin pass:"GNU Name System" -in $GNSCAKY -out $GNSCANO
@@ -46,7 +44,8 @@ cat $GNSCERT $GNSCANO > $GNS_CA_CERT_PEM
46 44
47if ! which certutil > /dev/null 45if ! which certutil > /dev/null
48then 46then
49 echo "'certutil' command not found. Not importing into browsers." 47 echo "The 'certutil' command was not found. Not importing into browsers."
48 echo "For 'certutil' install nss."
50else 49else
51 echo "Importing CA into browsers" 50 echo "Importing CA into browsers"
52 for f in ~/.mozilla/firefox/*.*/ 51 for f in ~/.mozilla/firefox/*.*/
diff --git a/src/gns/gnunet-gns-proxy.c b/src/gns/gnunet-gns-proxy.c
index 21451651d..65a7b6018 100644
--- a/src/gns/gnunet-gns-proxy.c
+++ b/src/gns/gnunet-gns-proxy.c
@@ -972,7 +972,7 @@ check_ssl_certificate (struct Socks5Request *s5r)
972 if (CURLE_OK != 972 if (CURLE_OK !=
973 curl_easy_getinfo (s5r->curl, 973 curl_easy_getinfo (s5r->curl,
974 CURLINFO_TLS_SESSION, 974 CURLINFO_TLS_SESSION,
975 (struct curl_slist **) &tlsinfo)) 975 &tlsinfo))
976 return GNUNET_SYSERR; 976 return GNUNET_SYSERR;
977 if (CURLSSLBACKEND_GNUTLS != tlsinfo->backend) 977 if (CURLSSLBACKEND_GNUTLS != tlsinfo->backend)
978 { 978 {
@@ -2045,11 +2045,12 @@ create_response (void *cls,
2045 const char *us; 2045 const char *us;
2046 long upload_size; 2046 long upload_size;
2047 2047
2048 upload_size = 0;
2048 us = MHD_lookup_connection_value (con, 2049 us = MHD_lookup_connection_value (con,
2049 MHD_HEADER_KIND, 2050 MHD_HEADER_KIND,
2050 MHD_HTTP_HEADER_CONTENT_LENGTH); 2051 MHD_HTTP_HEADER_CONTENT_LENGTH);
2051 if ( (NULL != us) && 2052 if ( (NULL != us) &&
2052 (1 == sscanf (us, 2053 (1 == sscanf (us,
2053 "%ld", 2054 "%ld",
2054 &upload_size)) && 2055 &upload_size)) &&
2055 (upload_size >= 0) ) 2056 (upload_size >= 0) )
@@ -2149,7 +2150,7 @@ create_response (void *cls,
2149 curl_easy_setopt (s5r->curl, 2150 curl_easy_setopt (s5r->curl,
2150 CURLOPT_USE_SSL, 2151 CURLOPT_USE_SSL,
2151 CURLUSESSL_ALL); 2152 CURLUSESSL_ALL);
2152 if (NULL != s5r->dane_data) 2153 if (0 < s5r->num_danes)
2153 curl_easy_setopt (s5r->curl, 2154 curl_easy_setopt (s5r->curl,
2154 CURLOPT_SSL_VERIFYPEER, 2155 CURLOPT_SSL_VERIFYPEER,
2155 0L); 2156 0L);
diff --git a/src/gns/openssl.cnf b/src/gns/openssl.cnf
new file mode 100644
index 000000000..503460f9f
--- /dev/null
+++ b/src/gns/openssl.cnf
@@ -0,0 +1,245 @@
1#
2# OpenSSL example configuration file.
3# This is mostly being used for generation of certificate requests.
4#
5
6# This definition stops the following lines choking if HOME isn't
7# defined.
8HOME = .
9RANDFILE = $ENV::HOME/.rnd
10
11# Extra OBJECT IDENTIFIER info:
12#oid_file = $ENV::HOME/.oid
13oid_section = new_oids
14
15# To use this configuration file with the "-extfile" option of the
16# "openssl x509" utility, name here the section containing the
17# X.509v3 extensions to use:
18# extensions =
19# (Alternatively, use a configuration file that has only
20# X.509v3 extensions in its main [= default] section.)
21
22[ new_oids ]
23
24# We can add new OIDs in here for use by 'ca' and 'req'.
25# Add a simple OID like this:
26# testoid1=1.2.3.4
27# Or use config file substitution like this:
28# testoid2=${testoid1}.5.6
29
30####################################################################
31[ ca ]
32default_ca = CA_default # The default ca section
33
34####################################################################
35[ CA_default ]
36
37dir = ./demoCA # Where everything is kept
38certs = $dir/certs # Where the issued certs are kept
39crl_dir = $dir/crl # Where the issued crl are kept
40database = $dir/index.txt # database index file.
41new_certs_dir = $dir/newcerts # default place for new certs.
42
43certificate = $dir/cacert.pem # The CA certificate
44serial = $dir/serial # The current serial number
45crl = $dir/crl.pem # The current CRL
46private_key = $dir/private/cakey.pem# The private key
47RANDFILE = $dir/private/.rand # private random number file
48
49x509_extensions = usr_cert # The extentions to add to the cert
50
51# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
52# so this is commented out by default to leave a V1 CRL.
53# crl_extensions = crl_ext
54
55default_days = 365 # how long to certify for
56default_crl_days= 30 # how long before next CRL
57default_md = md5 # which md to use.
58preserve = no # keep passed DN ordering
59
60# A few difference way of specifying how similar the request should look
61# For type CA, the listed attributes must be the same, and the optional
62# and supplied fields are just that :-)
63policy = policy_match
64
65# For the CA policy
66[ policy_match ]
67countryName = match
68stateOrProvinceName = match
69organizationName = match
70organizationalUnitName = optional
71commonName = supplied
72emailAddress = optional
73
74# For the 'anything' policy
75# At this point in time, you must list all acceptable 'object'
76# types.
77[ policy_anything ]
78countryName = optional
79stateOrProvinceName = optional
80localityName = optional
81organizationName = optional
82organizationalUnitName = optional
83commonName = supplied
84emailAddress = optional
85
86####################################################################
87[ req ]
88default_bits = 1024
89default_keyfile = privkey.pem
90distinguished_name = req_distinguished_name
91attributes = req_attributes
92x509_extensions = v3_ca # The extentions to add to the self signed cert
93
94# Passwords for private keys if not present they will be prompted for
95# input_password = secret
96# output_password = secret
97
98# This sets a mask for permitted string types. There are several options.
99# default: PrintableString, T61String, BMPString.
100# pkix : PrintableString, BMPString.
101# utf8only: only UTF8Strings.
102# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
103# MASK:XXXX a literal mask value.
104# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
105# so use this option with caution!
106string_mask = nombstr
107
108# req_extensions = v3_req # The extensions to add to a certificate request
109
110[ req_distinguished_name ]
111countryName = Country Name (2 letter code)
112countryName_default = AU
113countryName_min = 2
114countryName_max = 2
115
116stateOrProvinceName = State or Province Name (full name)
117stateOrProvinceName_default = Some-State
118
119localityName = Locality Name (eg, city)
120
1210.organizationName = Organization Name (eg, company)
1220.organizationName_default = Internet Widgits Pty Ltd
123
124# we can do this but it is not needed normally :-)
125#1.organizationName = Second Organization Name (eg, company)
126#1.organizationName_default = World Wide Web Pty Ltd
127
128organizationalUnitName = Organizational Unit Name (eg, section)
129#organizationalUnitName_default =
130
131commonName = Common Name (eg, YOUR name)
132commonName_max = 64
133
134emailAddress = Email Address
135emailAddress_max = 40
136
137# SET-ex3 = SET extension number 3
138
139[ req_attributes ]
140challengePassword = A challenge password
141challengePassword_min = 4
142challengePassword_max = 20
143
144unstructuredName = An optional company name
145
146[ usr_cert ]
147
148# These extensions are added when 'ca' signs a request.
149
150# This goes against PKIX guidelines but some CAs do it and some software
151# requires this to avoid interpreting an end user certificate as a CA.
152
153basicConstraints=CA:FALSE
154
155# Here are some examples of the usage of nsCertType. If it is omitted
156# the certificate can be used for anything *except* object signing.
157
158# This is OK for an SSL server.
159# nsCertType = server
160
161# For an object signing certificate this would be used.
162# nsCertType = objsign
163
164# For normal client use this is typical
165# nsCertType = client, email
166
167# and for everything including object signing:
168# nsCertType = client, email, objsign
169
170# This is typical in keyUsage for a client certificate.
171# keyUsage = nonRepudiation, digitalSignature, keyEncipherment
172
173# This will be displayed in Netscape's comment listbox.
174nsComment = "OpenSSL Generated Certificate"
175
176# PKIX recommendations harmless if included in all certificates.
177subjectKeyIdentifier=hash
178authorityKeyIdentifier=keyid,issuer:always
179
180# This stuff is for subjectAltName and issuerAltname.
181# Import the email address.
182# subjectAltName=email:copy
183
184# Copy subject details
185# issuerAltName=issuer:copy
186
187#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
188#nsBaseUrl
189#nsRevocationUrl
190#nsRenewalUrl
191#nsCaPolicyUrl
192#nsSslServerName
193
194[ v3_req ]
195
196# Extensions to add to a certificate request
197
198basicConstraints = CA:FALSE
199keyUsage = nonRepudiation, digitalSignature, keyEncipherment
200
201[ v3_ca ]
202
203
204# Extensions for a typical CA
205
206
207# PKIX recommendation.
208
209subjectKeyIdentifier=hash
210
211authorityKeyIdentifier=keyid:always,issuer:always
212
213# This is what PKIX recommends but some broken software chokes on critical
214# extensions.
215#basicConstraints = critical,CA:true
216# So we do this instead.
217basicConstraints = CA:true
218
219# Key usage: this is typical for a CA certificate. However since it will
220# prevent it being used as an test self-signed certificate it is best
221# left out by default.
222# keyUsage = cRLSign, keyCertSign
223
224# Some might want this also
225# nsCertType = sslCA, emailCA
226
227# Include email address in subject alt name: another PKIX recommendation
228# subjectAltName=email:copy
229# Copy issuer details
230# issuerAltName=issuer:copy
231
232# DER hex encoding of an extension: beware experts only!
233# obj=DER:02:03
234# Where 'obj' is a standard or added object
235# You can even override a supported extension:
236# basicConstraints= critical, DER:30:03:01:01:FF
237
238[ crl_ext ]
239
240# CRL extensions.
241# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
242
243# issuerAltName=issuer:copy
244authorityKeyIdentifier=keyid:always,issuer:always
245
diff --git a/src/gns/test_gns_nick_shorten.conf b/src/gns/test_gns_nick_shorten.conf
deleted file mode 100644
index 317477c80..000000000
--- a/src/gns/test_gns_nick_shorten.conf
+++ /dev/null
@@ -1,24 +0,0 @@
1@INLINE@ test_gns_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-gns-peer-1/
5
6[dht]
7START_ON_DEMAND = YES
8
9[transport]
10PLUGINS =
11
12[gns]
13#PREFIX = valgrind --leak-check=full --track-origins=yes
14START_ON_DEMAND = YES
15AUTO_IMPORT_PKEY = YES
16MAX_PARALLEL_BACKGROUND_QUERIES = 10
17DEFAULT_LOOKUP_TIMEOUT = 15 s
18RECORD_PUT_INTERVAL = 1 h
19ZONE_PUBLISH_TIME_WINDOW = 1 h
20DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0
21#USE_CACHE = NO
22
23[revocation]
24WORKBITS = 1
diff --git a/src/gns/test_gns_rel_expiration.sh b/src/gns/test_gns_rel_expiration.sh
index 66adbb631..c7c66bc27 100755
--- a/src/gns/test_gns_rel_expiration.sh
+++ b/src/gns/test_gns_rel_expiration.sh
@@ -7,6 +7,13 @@ if [ -z $LOCATION ]
7then 7then
8 LOCATION="gnunet-config" 8 LOCATION="gnunet-config"
9fi 9fi
10
11if [ -z $(which timeout) ]
12then
13 echo "timeout utility not found which is required for test."
14 exit 77
15fi
16
10$LOCATION --version 1> /dev/null 17$LOCATION --version 1> /dev/null
11if test $? != 0 18if test $? != 0
12then 19then
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
index 195cac075..4e84e023c 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -33,6 +33,7 @@ gnunetinclude_HEADERS = \
33 gnunet_ats_application_service.h \ 33 gnunet_ats_application_service.h \
34 gnunet_ats_transport_service.h \ 34 gnunet_ats_transport_service.h \
35 gnunet_ats_plugin.h \ 35 gnunet_ats_plugin.h \
36 gnunet_ats_plugin_new.h \
36 gnunet_bandwidth_lib.h \ 37 gnunet_bandwidth_lib.h \
37 gnunet_bio_lib.h \ 38 gnunet_bio_lib.h \
38 gnunet_block_lib.h \ 39 gnunet_block_lib.h \
@@ -58,7 +59,6 @@ gnunetinclude_HEADERS = \
58 gnunet_dnsparser_lib.h \ 59 gnunet_dnsparser_lib.h \
59 gnunet_dnsstub_lib.h \ 60 gnunet_dnsstub_lib.h \
60 gnunet_dns_service.h \ 61 gnunet_dns_service.h \
61 gnunet_dv_service.h \
62 gnunet_fragmentation_lib.h \ 62 gnunet_fragmentation_lib.h \
63 gnunet_friends_lib.h \ 63 gnunet_friends_lib.h \
64 gnunet_fs_service.h \ 64 gnunet_fs_service.h \
@@ -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,19 +100,13 @@ 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 \
114 gnunet_regex_service.h \ 106 gnunet_regex_service.h \
115 gnunet_rest_lib.h \ 107 gnunet_rest_lib.h \
116 gnunet_rest_plugin.h \ 108 gnunet_rest_plugin.h \
109 gnunet_rps_service.h \
117 gnunet_revocation_service.h \ 110 gnunet_revocation_service.h \
118 gnunet_scalarproduct_service.h \ 111 gnunet_scalarproduct_service.h \
119 gnunet_scheduler_lib.h \ 112 gnunet_scheduler_lib.h \
@@ -122,7 +115,6 @@ gnunetinclude_HEADERS = \
122 gnunet_set_service.h \ 115 gnunet_set_service.h \
123 gnunet_signal_lib.h \ 116 gnunet_signal_lib.h \
124 gnunet_signatures.h \ 117 gnunet_signatures.h \
125 gnunet_social_service.h \
126 gnunet_socks.h \ 118 gnunet_socks.h \
127 gnunet_speaker_lib.h \ 119 gnunet_speaker_lib.h \
128 gnunet_sq_lib.h \ 120 gnunet_sq_lib.h \
@@ -133,6 +125,7 @@ gnunetinclude_HEADERS = \
133 gnunet_testing_lib.h \ 125 gnunet_testing_lib.h \
134 gnunet_time_lib.h \ 126 gnunet_time_lib.h \
135 gnunet_transport_service.h \ 127 gnunet_transport_service.h \
128 gnunet_transport_address_service.h \
136 gnunet_transport_communication_service.h \ 129 gnunet_transport_communication_service.h \
137 gnunet_transport_core_service.h \ 130 gnunet_transport_core_service.h \
138 gnunet_transport_hello_service.h \ 131 gnunet_transport_hello_service.h \
diff --git a/src/include/gnunet_cadet_service.h b/src/include/gnunet_cadet_service.h
index ac3d11216..b8326657d 100644
--- a/src/include/gnunet_cadet_service.h
+++ b/src/include/gnunet_cadet_service.h
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -369,7 +369,7 @@ GNUNET_CADET_channel_get_info (struct GNUNET_CADET_Channel *channel,
369 369
370/** 370/**
371 * Internal details about a channel. 371 * Internal details about a channel.
372 */ 372 */
373struct GNUNET_CADET_ChannelInternals 373struct GNUNET_CADET_ChannelInternals
374{ 374{
375 /** 375 /**
@@ -431,7 +431,7 @@ GNUNET_CADET_get_channel_cancel (struct GNUNET_CADET_ChannelMonitor *cm);
431 431
432/** 432/**
433 * Information we return per peer. 433 * Information we return per peer.
434 */ 434 */
435struct GNUNET_CADET_PeerListEntry 435struct GNUNET_CADET_PeerListEntry
436{ 436{
437 /** 437 /**
@@ -446,7 +446,7 @@ struct GNUNET_CADET_PeerListEntry
446 446
447 /** 447 /**
448 * Number of disjoint known paths to @e peer. 448 * Number of disjoint known paths to @e peer.
449 */ 449 */
450 unsigned int n_paths; 450 unsigned int n_paths;
451 451
452 /** 452 /**
@@ -504,7 +504,7 @@ GNUNET_CADET_list_peers_cancel (struct GNUNET_CADET_PeersLister *pl);
504 504
505/** 505/**
506 * Detailed information we return per peer. 506 * Detailed information we return per peer.
507 */ 507 */
508struct GNUNET_CADET_PeerPathDetail 508struct GNUNET_CADET_PeerPathDetail
509{ 509{
510 /** 510 /**
@@ -513,6 +513,11 @@ struct GNUNET_CADET_PeerPathDetail
513 struct GNUNET_PeerIdentity peer; 513 struct GNUNET_PeerIdentity peer;
514 514
515 /** 515 /**
516 * Offset of the target peer on the @e path.
517 */
518 unsigned int target_offset;
519
520 /**
516 * Number of entries on the @e path. 521 * Number of entries on the @e path.
517 */ 522 */
518 unsigned int path_length; 523 unsigned int path_length;
@@ -583,7 +588,7 @@ struct GNUNET_CADET_TunnelDetails
583 588
584 /** 589 /**
585 * How many channels use the tunnel. 590 * How many channels use the tunnel.
586 */ 591 */
587 uint32_t channels; 592 uint32_t channels;
588 593
589 /** 594 /**
@@ -597,8 +602,8 @@ struct GNUNET_CADET_TunnelDetails
597 uint16_t estate; 602 uint16_t estate;
598 603
599 /** 604 /**
600 * What is our connectivity state? 605 * What is our connectivity state?
601 */ 606 */
602 uint16_t cstate; 607 uint16_t cstate;
603}; 608};
604 609
diff --git a/src/include/gnunet_common.h b/src/include/gnunet_common.h
index e482e5ebe..ca49d3109 100644
--- a/src/include/gnunet_common.h
+++ b/src/include/gnunet_common.h
@@ -119,6 +119,7 @@ extern "C"
119 */ 119 */
120#define GNUNET_VA_ARG_ENUM(va,X) ((enum X) va_arg (va, int)) 120#define GNUNET_VA_ARG_ENUM(va,X) ((enum X) va_arg (va, int))
121 121
122
122/** 123/**
123 * @ingroup logging 124 * @ingroup logging
124 * define #GNUNET_EXTRA_LOGGING if using this header outside the GNUnet source 125 * define #GNUNET_EXTRA_LOGGING if using this header outside the GNUnet source
@@ -410,7 +411,7 @@ GNUNET_get_log_call_status (int caller_level,
410 */ 411 */
411void 412void
412GNUNET_log_nocheck (enum GNUNET_ErrorType kind, const char *message, ...) 413GNUNET_log_nocheck (enum GNUNET_ErrorType kind, const char *message, ...)
413 __attribute__ ((format (gnu_printf, 2, 3))); 414 __attribute__ ((format (printf, 2, 3)));
414 415
415/* from glib */ 416/* from glib */
416#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) 417#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
diff --git a/src/include/gnunet_dv_service.h b/src/include/gnunet_dv_service.h
deleted file mode 100644
index 334912773..000000000
--- a/src/include/gnunet_dv_service.h
+++ /dev/null
@@ -1,166 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013, 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 * @author Christian Grothoff
23 *
24 * @file
25 * DV service API (should only be used by the DV plugin)
26 *
27 * @defgroup dv DV service
28 * Distance Vector routing
29 *
30 * The DV service API should only be used by the DV plugin.
31 * @{
32 */
33#ifndef GNUNET_SERVICE_DV_H
34#define GNUNET_SERVICE_DV_H
35
36#include "gnunet_util_lib.h"
37#include "gnunet_ats_service.h"
38
39/**
40 * Signature of a function to be called if DV
41 * starts to be able to talk to a peer.
42 *
43 * @param cls closure
44 * @param peer newly connected peer
45 * @param distance distance to the peer
46 * @param network the peer is located in
47 */
48typedef void
49(*GNUNET_DV_ConnectCallback)(void *cls,
50 const struct GNUNET_PeerIdentity *peer,
51 uint32_t distance,
52 enum GNUNET_NetworkType network);
53
54
55/**
56 * Signature of a function to be called if DV
57 * distance to a peer is changed.
58 *
59 * @param cls closure
60 * @param peer connected peer
61 * @param distance new distance to the peer
62 * @param network this network will be used to reach the next hop
63 */
64typedef void
65(*GNUNET_DV_DistanceChangedCallback)(void *cls,
66 const struct GNUNET_PeerIdentity *peer,
67 uint32_t distance,
68 enum GNUNET_NetworkType network);
69
70
71/**
72 * Signature of a function to be called if DV
73 * is no longer able to talk to a peer.
74 *
75 * @param cls closure
76 * @param peer peer that disconnected
77 */
78typedef void
79(*GNUNET_DV_DisconnectCallback)(void *cls,
80 const struct GNUNET_PeerIdentity *peer);
81
82
83/**
84 * Signature of a function to be called if DV
85 * receives a message for this peer.
86 *
87 * @param cls closure
88 * @param sender sender of the message
89 * @param distance how far did the message travel
90 * @param msg actual message payload
91 */
92typedef void
93(*GNUNET_DV_MessageReceivedCallback)(void *cls,
94 const struct GNUNET_PeerIdentity *sender,
95 uint32_t distance,
96 const struct GNUNET_MessageHeader *msg);
97
98
99/**
100 * Signature of a function called once the delivery of a
101 * message has been successful.
102 *
103 * @param cls closure
104 */
105typedef void
106(*GNUNET_DV_MessageSentCallback)(void *cls);
107
108
109/**
110 * Handle to the DV service.
111 */
112struct GNUNET_DV_ServiceHandle;
113
114
115/**
116 * Connect to the DV service.
117 *
118 * @param cfg configuration
119 * @param cls closure for callbacks
120 * @param connect_cb function to call on connects
121 * @param distance_cb function to call if distances change
122 * @param disconnect_cb function to call on disconnects
123 * @param message_cb function to call if we receive messages
124 * @return handle to access the service
125 */
126struct GNUNET_DV_ServiceHandle *
127GNUNET_DV_service_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
128 void *cls,
129 GNUNET_DV_ConnectCallback connect_cb,
130 GNUNET_DV_DistanceChangedCallback distance_cb,
131 GNUNET_DV_DisconnectCallback disconnect_cb,
132 GNUNET_DV_MessageReceivedCallback message_cb);
133
134
135/**
136 * Disconnect from DV service.
137 *
138 * @param sh service handle
139 */
140void
141GNUNET_DV_service_disconnect (struct GNUNET_DV_ServiceHandle *sh);
142
143
144/**
145 * Handle for a send operation.
146 */
147struct GNUNET_DV_TransmitHandle;
148
149
150/**
151 * Send a message via DV service.
152 *
153 * @param sh service handle
154 * @param target intended recpient
155 * @param msg message payload
156 * @return handle to cancel the operation
157 */
158void
159GNUNET_DV_send (struct GNUNET_DV_ServiceHandle *sh,
160 const struct GNUNET_PeerIdentity *target,
161 const struct GNUNET_MessageHeader *msg);
162
163
164#endif
165
166/** @} */ /* end of group */
diff --git a/src/include/gnunet_hello_lib.h b/src/include/gnunet_hello_lib.h
index c2256fd0a..fcd422701 100644
--- a/src/include/gnunet_hello_lib.h
+++ b/src/include/gnunet_hello_lib.h
@@ -526,7 +526,7 @@ GNUNET_HELLO_extract_address (const void *raw,
526 * 526 *
527 * @param address a peer's address 527 * @param address a peer's address
528 * @return NULL if the address is mal-formed, otherwise the prefix 528 * @return NULL if the address is mal-formed, otherwise the prefix
529 */ 529 */
530char * 530char *
531GNUNET_HELLO_address_to_prefix (const char *address); 531GNUNET_HELLO_address_to_prefix (const char *address);
532 532
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_namestore_plugin.h b/src/include/gnunet_namestore_plugin.h
index 46a7da792..3b603b4c0 100644
--- a/src/include/gnunet_namestore_plugin.h
+++ b/src/include/gnunet_namestore_plugin.h
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -47,7 +47,8 @@ extern "C"
47 * Function called for each matching record. 47 * Function called for each matching record.
48 * 48 *
49 * @param cls closure 49 * @param cls closure
50 * @param serial unique serial number of the record 50 * @param serial unique serial number of the record, MUST NOT BE ZERO,
51 * and must be monotonically increasing while iterating
51 * @param zone_key private key of the zone 52 * @param zone_key private key of the zone
52 * @param label name that is being mapped (at most 255 characters long) 53 * @param label name that is being mapped (at most 255 characters long)
53 * @param rd_count number of entries in @a rd array 54 * @param rd_count number of entries in @a rd array
@@ -115,7 +116,9 @@ struct GNUNET_NAMESTORE_PluginFunctions
115 * 116 *
116 * @param cls closure (internal context for the plugin) 117 * @param cls closure (internal context for the plugin)
117 * @param zone private key of the zone, NULL for all zones 118 * @param zone private key of the zone, NULL for all zones
118 * @param serial serial (to exclude) in the list of matching records 119 * @param serial serial (to exclude) in the list of matching records;
120 * 0 means to exclude nothing; results must be returned using
121 * the minimum possible sequence number first (ordered by serial)
119 * @param limit maximum number of results to return to @a iter 122 * @param limit maximum number of results to return to @a iter
120 * @param iter function to call with the result 123 * @param iter function to call with the result
121 * @param iter_cls closure for @a iter 124 * @param iter_cls closure for @a iter
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h
index 793430184..46620b829 100644
--- a/src/include/gnunet_protocols.h
+++ b/src/include/gnunet_protocols.h
@@ -2633,7 +2633,7 @@ extern "C"
2633 */ 2633 */
2634#define GNUNET_MESSAGE_TYPE_RPS_CS_SEED 954 2634#define GNUNET_MESSAGE_TYPE_RPS_CS_SEED 954
2635 2635
2636#ifdef ENABLE_MALICIOUS 2636#if ENABLE_MALICIOUS
2637/** 2637/**
2638 * Turn RPS service malicious 2638 * Turn RPS service malicious
2639 */ 2639 */
@@ -3106,40 +3106,47 @@ extern "C"
3106/** 3106/**
3107 * Type of a fragment of a CORE message created by transport to adjust 3107 * Type of a fragment of a CORE message created by transport to adjust
3108 * message length to a queue's MTU. 3108 * message length to a queue's MTU.
3109 */ 3109 */
3110#define GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT 1214 3110#define GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT 1214
3111 3111
3112/** 3112/**
3113 * Acknowledgement generated for a fragment. 3113 * Acknowledgement generated for a fragment.
3114 */ 3114 */
3115#define GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK 1215 3115#define GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK 1215
3116 3116
3117/** 3117/**
3118 * Wrapper around non-fragmented CORE message used to measure RTT 3118 * Wrapper around non-fragmented CORE message used to measure RTT
3119 * and ensure reliability. 3119 * and ensure reliability.
3120 */ 3120 */
3121#define GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX 1216 3121#define GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX 1216
3122 3122
3123/** 3123/**
3124 * Confirmation for a #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. 3124 * Confirmation for a #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX.
3125 */ 3125 */
3126#define GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK 1217 3126#define GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK 1217
3127 3127
3128/** 3128/**
3129 * Message sent for topology discovery at transport level. 3129 * Message sent for topology discovery at transport level.
3130 */ 3130 */
3131#define GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN 1218 3131#define GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN 1218
3132 3132
3133/** 3133/**
3134 * Source-routed transport message based DV information gathered. 3134 * Source-routed transport message based DV information gathered.
3135 */ 3135 */
3136#define GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX 1219 3136#define GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX 1219
3137 3137
3138/** 3138/**
3139 * Transport signalling incoming backchannel message to a communicator. 3139 * Transport signalling incoming backchannel message to a communicator.
3140 */ 3140 */
3141#define GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING 1220 3141#define GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING 1220
3142 3142
3143/**
3144 * We learned a possible network address of another peer. Transport
3145 * should consider verifying it, and if successful, remembering it
3146 * in the Peerstore.
3147 */
3148#define GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY 1221
3149
3143 3150
3144/** 3151/**
3145 * Message sent to indicate to the transport that a monitor 3152 * Message sent to indicate to the transport that a monitor
@@ -3230,7 +3237,7 @@ extern "C"
3230 3237
3231/** 3238/**
3232 * TCP communicator end of stream. 3239 * TCP communicator end of stream.
3233 */ 3240 */
3234#define GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_FINISH 1452 3241#define GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_FINISH 1452
3235 3242
3236/** 3243/**
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_rps_service.h b/src/include/gnunet_rps_service.h
index 8ae9f1e93..b1dd1b5af 100644
--- a/src/include/gnunet_rps_service.h
+++ b/src/include/gnunet_rps_service.h
@@ -137,7 +137,7 @@ GNUNET_RPS_seed_ids (struct GNUNET_RPS_Handle *h, uint32_t n,
137GNUNET_RPS_request_cancel (struct GNUNET_RPS_Request_Handle *rh); 137GNUNET_RPS_request_cancel (struct GNUNET_RPS_Request_Handle *rh);
138 138
139 139
140#ifdef ENABLE_MALICIOUS 140#if ENABLE_MALICIOUS
141/** 141/**
142 * Turn RPS service to act malicious. 142 * Turn RPS service to act malicious.
143 * 143 *
diff --git a/src/include/gnunet_sensor_service.h b/src/include/gnunet_sensor_service.h
deleted file mode 100644
index 391db58bf..000000000
--- a/src/include/gnunet_sensor_service.h
+++ /dev/null
@@ -1,199 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C)
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 Omar Tarabai
23 *
24 * @file
25 * API to the sensor service
26 *
27 * @defgroup sensor Sensor service
28 *
29 * @{
30 */
31
32#ifndef GNUNET_SENSOR_SERVICE_H
33#define GNUNET_SENSOR_SERVICE_H
34
35#include "gnunet_common.h"
36#include "gnunet_util_lib.h"
37
38#ifdef __cplusplus
39extern "C"
40{
41#if 0 /* keep Emacsens' auto-indent happy */
42}
43#endif
44#endif
45
46
47/**
48 * Handle to the sensor service.
49 */
50struct GNUNET_SENSOR_Handle;
51
52/**
53 * Context for an iteration request.
54 */
55struct GNUNET_SENSOR_IterateContext;
56
57/**
58 * Context of a force anomaly request
59 */
60struct GNUNET_SENSOR_ForceAnomalyContext;
61
62/**
63 * Structure containing brief info about sensor
64 */
65struct SensorInfoShort
66{
67
68 /*
69 * Sensor name
70 */
71 char *name;
72
73 /*
74 * First part of version number
75 */
76 uint16_t version_major;
77
78 /*
79 * Second part of version number
80 */
81 uint16_t version_minor;
82
83 /*
84 * Sensor description
85 */
86 char *description;
87
88};
89
90/**
91 * Sensor iterate request callback.
92 *
93 * @param cls closure
94 * @param sensor Brief sensor information
95 * @param error message
96 */
97typedef void (*GNUNET_SENSOR_SensorIterateCB) (void *cls,
98 const struct SensorInfoShort *
99 sensor, const char *err_msg);
100
101
102/**
103 * Continuation called with a status result.
104 *
105 * @param cls closure
106 * @param emsg error message, NULL on success
107 */
108typedef void (*GNUNET_SENSOR_Continuation) (void *cls, const char *emsg);
109
110
111/**
112 * Disconnect from the sensor service
113 *
114 * @param h handle to disconnect
115 */
116void
117GNUNET_SENSOR_disconnect (struct GNUNET_SENSOR_Handle *h);
118
119
120/**
121 * Connect to the sensor service.
122 *
123 * @return NULL on error
124 */
125struct GNUNET_SENSOR_Handle *
126GNUNET_SENSOR_connect (const struct GNUNET_CONFIGURATION_Handle *cfg);
127
128
129/**
130 * Cancel an iteration request.
131 * This should be called before the iterate callback is called with a NULL value.
132 *
133 * @param ic context of the iterator to cancel
134 */
135void
136GNUNET_SENSOR_iterate_cancel (struct GNUNET_SENSOR_IterateContext
137 *ic);
138
139
140/**
141 * Get one or all sensors loaded by the sensor service.
142 * The callback will be called with each sensor received and once with a NULL
143 * value to signal end of iteration.
144 *
145 * @param h Handle to SENSOR service
146 * @param timeout how long to wait until timing out
147 * @param sensorname Name of the required sensor, NULL to get all
148 * @param callback the function to call for each sensor
149 * @param callback_cls closure for callback
150 * @return iterator context
151 */
152struct GNUNET_SENSOR_IterateContext *
153GNUNET_SENSOR_iterate (struct GNUNET_SENSOR_Handle *h,
154 struct GNUNET_TIME_Relative timeout,
155 const char *sensor_name,
156 GNUNET_SENSOR_SensorIterateCB callback,
157 void *callback_cls);
158
159
160/**
161 * Cancel a force anomaly request.
162 *
163 * @param fa Force anomaly context returned by GNUNET_SENSOR_force_anomaly()
164 */
165void
166GNUNET_SENSOR_force_anomaly_cancel (struct GNUNET_SENSOR_ForceAnomalyContext
167 *fa);
168
169
170/**
171 * Force an anomaly status change on a given sensor. If the sensor reporting
172 * module is running, this will trigger the usual reporting logic, therefore,
173 * please only use this in a test environment.
174 *
175 * Also, if the sensor analysis module is running, it might conflict and cause
176 * undefined behaviour if it detects a real anomaly.
177 *
178 * @param h Service handle
179 * @param sensor_name Sensor name to set the anomaly status
180 * @param anomalous The desired status: #GNUNET_YES / #GNUNET_NO
181 * @param cont Continuation function to be called after the request is sent
182 * @param cont_cls Closure for cont
183 */
184struct GNUNET_SENSOR_ForceAnomalyContext *
185GNUNET_SENSOR_force_anomaly (struct GNUNET_SENSOR_Handle *h, char *sensor_name,
186 int anomalous, GNUNET_SENSOR_Continuation cont,
187 void *cont_cls);
188
189
190#if 0 /* keep Emacsens' auto-indent happy */
191{
192#endif
193#ifdef __cplusplus
194}
195#endif
196
197#endif
198
199/** @} */ /* end of group */
diff --git a/src/include/gnunet_sensor_util_lib.h b/src/include/gnunet_sensor_util_lib.h
deleted file mode 100644
index f4eaad9e8..000000000
--- a/src/include/gnunet_sensor_util_lib.h
+++ /dev/null
@@ -1,520 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C)
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 Omar Tarabai
23 *
24 * @file
25 * Sensor utilities
26 *
27 * @defgroup sensor Sensor Utilities library
28 *
29 * @{
30 */
31
32#ifndef GNUNET_SENSOR_UTIL_LIB_H
33#define GNUNET_SENSOR_UTIL_LIB_H
34
35#ifdef __cplusplus
36extern "C"
37{
38#if 0 /* keep Emacsens' auto-indent happy */
39}
40#endif
41#endif
42
43/**
44 * Structure containing sensor definition
45 */
46struct GNUNET_SENSOR_SensorInfo
47{
48
49 /**
50 * The configuration handle
51 * carrying sensor information
52 */
53 struct GNUNET_CONFIGURATION_Handle *cfg;
54
55 /**
56 * Sensor name
57 */
58 char *name;
59
60 /**
61 * Path to definition file
62 */
63 char *def_file;
64
65 /**
66 * First part of version number
67 */
68 uint16_t version_major;
69
70 /**
71 * Second part of version number
72 */
73 uint16_t version_minor;
74
75 /**
76 * Sensor description
77 */
78 char *description;
79
80 /**
81 * Sensor currently enabled
82 */
83 int enabled;
84
85 /**
86 * Category under which the sensor falls (e.g. tcp, datastore)
87 */
88 char *category;
89
90 /**
91 * When does the sensor become active
92 */
93 struct GNUNET_TIME_Absolute *start_time;
94
95 /**
96 * When does the sensor expire
97 */
98 struct GNUNET_TIME_Absolute *end_time;
99
100 /**
101 * Time interval to collect sensor information (e.g. every 1 min)
102 */
103 struct GNUNET_TIME_Relative interval;
104
105 /**
106 * Lifetime of an information sample after which it is deleted from storage
107 * If not supplied, will default to the interval value
108 */
109 struct GNUNET_TIME_Relative lifetime;
110
111 /**
112 * A set of required peer capabilities for the sensor to collect meaningful information (e.g. ipv6)
113 */
114 char *capabilities;
115
116 /**
117 * Either "gnunet-statistics" or external "process"
118 */
119 char *source;
120
121 /**
122 * Name of the GNUnet service that is the source for the gnunet-statistics entry
123 */
124 char *gnunet_stat_service;
125
126 /**
127 * Name of the gnunet-statistics entry
128 */
129 char *gnunet_stat_name;
130
131 /**
132 * Handle to statistics get request (OR NULL)
133 */
134 struct GNUNET_STATISTICS_GetHandle *gnunet_stat_get_handle;
135
136 /**
137 * Name of the external process to be executed
138 */
139 char *ext_process;
140
141 /**
142 * Arguments to be passed to the external process
143 */
144 char *ext_args;
145
146 /**
147 * Handle to the external process
148 */
149 struct GNUNET_OS_CommandHandle *ext_cmd;
150
151 /**
152 * Did we already receive a value
153 * from the currently running external
154 * proccess ? #GNUNET_YES / #GNUNET_NO
155 */
156 int ext_cmd_value_received;
157
158 /**
159 * The output datatype to be expected
160 */
161 char *expected_datatype;
162
163 /**
164 * Peer-identity of peer running collection point
165 */
166 struct GNUNET_PeerIdentity *collection_point;
167
168 /**
169 * Do we report received sensor values to collection point?
170 * #GNUNET_YES / #GNUNET_NO
171 */
172 int report_values;
173
174 /**
175 * Time interval to send sensor values to collection point (e.g. every 30 mins)
176 */
177 struct GNUNET_TIME_Relative value_reporting_interval;
178
179 /**
180 * Do we report anomalies to collection point?
181 * #GNUNET_YES / #GNUNET_NO
182 */
183 int report_anomalies;
184
185 /**
186 * Execution task (OR NULL)
187 */
188 struct GNUNET_SCHEDULER_Task * execution_task;
189
190 /**
191 * Is the sensor being executed
192 */
193 int running;
194
195};
196
197/**
198 * Anomaly report received and stored by sensor dashboard.
199 * Sensor name and peer id are not included because they are part of the
200 * peerstore key.
201 */
202struct GNUNET_SENSOR_DashboardAnomalyEntry
203{
204
205 /**
206 * New anomaly status
207 */
208 uint16_t anomalous;
209
210 /**
211 * Percentage of neighbors reported the same anomaly
212 */
213 float anomalous_neighbors;
214
215};
216
217GNUNET_NETWORK_STRUCT_BEGIN
218/**
219 * Used to communicate brief information about a sensor.
220 */
221 struct GNUNET_SENSOR_SensorBriefMessage
222{
223
224 /**
225 * GNUNET general message header.
226 */
227 struct GNUNET_MessageHeader header;
228
229 /**
230 * Size of sensor name string, allocated at position 0 after this struct.
231 */
232 uint16_t name_size;
233
234 /**
235 * First part of sensor version number
236 */
237 uint16_t version_major;
238
239 /**
240 * Second part of sensor version number
241 */
242 uint16_t version_minor;
243
244};
245
246/**
247 * Used to communicate full information about a sensor.
248 */
249struct GNUNET_SENSOR_SensorFullMessage
250{
251
252 /**
253 * GNUNET general message header.
254 */
255 struct GNUNET_MessageHeader header;
256
257 /**
258 * Size of sensor name.
259 * Name allocated at position 0 after this struct.
260 */
261 uint16_t sensorname_size;
262
263 /**
264 * Size of the sensor definition file carrying full sensor information.
265 * The file content allocated at position 1 after this struct.
266 */
267 uint16_t sensorfile_size;
268
269 /**
270 * Name of the file (usually script) associated with this sensor.
271 * At the moment we only support having one file per sensor.
272 * The file name is allocated at position 2 after this struct.
273 */
274 uint16_t scriptname_size;
275
276 /**
277 * Size of the file (usually script) associated with this sensor.
278 * The file content is allocated at position 3 after this struct.
279 */
280 uint16_t scriptfile_size;
281
282};
283
284/**
285 * Used to communicate sensor values to
286 * collection points (SENSORDASHBAORD service)
287 */
288struct GNUNET_SENSOR_ValueMessage
289{
290
291 /**
292 * GNUNET general message header
293 */
294 struct GNUNET_MessageHeader header;
295
296 /**
297 * Hash of sensor name
298 */
299 struct GNUNET_HashCode sensorname_hash;
300
301 /**
302 * First part of sensor version number
303 */
304 uint16_t sensorversion_major;
305
306 /**
307 * Second part of sensor version number
308 */
309 uint16_t sensorversion_minor;
310
311 /**
312 * Timestamp of recorded reading
313 */
314 struct GNUNET_TIME_Absolute timestamp;
315
316 /**
317 * Size of sensor value, allocated at poistion 0 after this struct
318 */
319 uint16_t value_size;
320
321};
322
323/**
324 * Message carrying an anomaly status change report
325 */
326struct GNUNET_SENSOR_AnomalyReportMessage
327{
328
329 /**
330 * Hash of sensor name
331 */
332 struct GNUNET_HashCode sensorname_hash;
333
334 /**
335 * First part of sensor version number
336 */
337 uint16_t sensorversion_major;
338
339 /**
340 * Second part of sensor version name
341 */
342 uint16_t sensorversion_minor;
343
344 /**
345 * New anomaly status
346 */
347 uint16_t anomalous;
348
349 /**
350 * Percentage of neighbors reported the same anomaly
351 */
352 float anomalous_neighbors;
353
354};
355
356GNUNET_NETWORK_STRUCT_END
357/**
358 * Given two version numbers as major and minor, compare them.
359 *
360 * @param v1_major First part of first version number
361 * @param v1_minor Second part of first version number
362 * @param v2_major First part of second version number
363 * @param v2_minor Second part of second version number
364 */
365 int
366GNUNET_SENSOR_version_compare (uint16_t v1_major, uint16_t v1_minor,
367 uint16_t v2_major, uint16_t v2_minor);
368
369
370/**
371 * Reads sensor definitions from given sensor directory.
372 *
373 * @param sensordir Path to sensor directory.
374 * @return a multihashmap of loaded sensors
375 */
376struct GNUNET_CONTAINER_MultiHashMap *
377GNUNET_SENSOR_load_all_sensors (char *sensor_dir);
378
379
380/**
381 * Get path to the default directory containing the sensor definition files with
382 * a trailing directory separator.
383 *
384 * @return Default sensor files directory full path
385 */
386char *
387GNUNET_SENSOR_get_default_sensor_dir ();
388
389
390/**
391 * Destroys a group of sensors in a hashmap and the hashmap itself
392 *
393 * @param sensors hashmap containing the sensors
394 */
395void
396GNUNET_SENSOR_destroy_sensors (struct GNUNET_CONTAINER_MultiHashMap *sensors);
397
398
399struct GNUNET_SENSOR_crypto_pow_context;
400
401/**
402 * Block carrying arbitrary data + its proof-of-work + signature
403 */
404struct GNUNET_SENSOR_crypto_pow_block
405{
406
407 /**
408 * Proof-of-work value
409 */
410 uint64_t pow;
411
412 /**
413 * Data signature
414 */
415 struct GNUNET_CRYPTO_EddsaSignature signature;
416
417 /**
418 * Size of the msg component (allocated after this struct)
419 */
420 size_t msg_size;
421
422 /**
423 * Purpose of signing.
424 * Data is allocated after this (timestamp, public_key, msg).
425 */
426 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
427
428 /**
429 * First part of data - timestamp
430 */
431 struct GNUNET_TIME_Absolute timestamp;
432
433 /**
434 * Second part of data - Public key
435 */
436 struct GNUNET_CRYPTO_EddsaPublicKey public_key;
437
438};
439
440
441/**
442 * Continuation called with a status result.
443 *
444 * @param cls closure
445 * @param pow Proof-of-work value
446 * @param purpose Signed block (size, purpose, data)
447 * @param signature Signature, NULL on error
448 */
449typedef void (*GNUNET_SENSOR_UTIL_pow_callback) (void *cls,
450 struct
451 GNUNET_SENSOR_crypto_pow_block
452 * block);
453
454
455/**
456 * Cancel an operation started by #GNUNET_SENSOR_crypto_pow_sign().
457 * Call only before callback function passed to #GNUNET_SENSOR_crypto_pow_sign()
458 * is called with the result.
459 */
460void
461GNUNET_SENSOR_crypto_pow_sign_cancel (struct GNUNET_SENSOR_crypto_pow_context
462 *cx);
463
464
465/**
466 * Calculate proof-of-work and sign a message.
467 *
468 * @param msg Message to calculate pow and sign
469 * @param msg_size size of msg
470 * @param timestamp Timestamp to add to the message to protect against replay attacks
471 * @param public_key Public key of the origin peer, to protect against redirect attacks
472 * @param private_key Private key of the origin peer to sign the result
473 * @param matching_bits Number of leading zeros required in the result hash
474 * @param callback Callback function to call with the result
475 * @param callback_cls Closure for callback
476 * @return Operation context
477 */
478struct GNUNET_SENSOR_crypto_pow_context *
479GNUNET_SENSOR_crypto_pow_sign (void *msg, size_t msg_size,
480 struct GNUNET_TIME_Absolute *timestamp,
481 struct GNUNET_CRYPTO_EddsaPublicKey *public_key,
482 struct GNUNET_CRYPTO_EddsaPrivateKey
483 *private_key, int matching_bits,
484 GNUNET_SENSOR_UTIL_pow_callback callback,
485 void *callback_cls);
486
487
488/**
489 * Verify that proof-of-work and signature in the given block are valid.
490 * If all valid, a pointer to the payload within the block is set and the size
491 * of the payload is returned.
492 *
493 * **VERY IMPORTANT** : You will still need to verify the timestamp yourself.
494 *
495 * @param block The block received and needs to be verified
496 * @param matching_bits Number of leading zeros in the hash used to verify pow
497 * @param public_key Public key of the peer that sent this block
498 * @param payload Where to store the pointer to the payload
499 * @return Size of the payload
500 */
501size_t
502GNUNET_SENSOR_crypto_verify_pow_sign (struct GNUNET_SENSOR_crypto_pow_block *
503 block, int matching_bits,
504 struct GNUNET_CRYPTO_EddsaPublicKey *
505 public_key, void **payload);
506
507
508#if 0 /* keep Emacsens' auto-indent happy */
509{
510#endif
511#ifdef __cplusplus
512}
513#endif
514
515/* ifndef GNUNET_SENSOR_UTIL_LIB_H */
516#endif
517
518/** @} */ /* end of group */
519
520/* end of gnunet_sensor_util_lib.h */
diff --git a/src/include/gnunet_sensordashboard_service.h b/src/include/gnunet_sensordashboard_service.h
deleted file mode 100644
index ffa24e3b7..000000000
--- a/src/include/gnunet_sensordashboard_service.h
+++ /dev/null
@@ -1,55 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C)
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 Omar Tarabai
23 *
24 * @file
25 * API to the sensordashboard service
26 *
27 * @defgroup sensordashboard Sensor Dashboard service
28 *
29 * @{
30 */
31#ifndef GNUNET_SENSORDASHBOARD_SERVICE_H
32#define GNUNET_SENSORDASHBOARD_SERVICE_H
33
34#include "gnunet_common.h"
35#include "gnunet_util_lib.h"
36
37#ifdef __cplusplus
38extern "C"
39{
40#if 0 /* keep Emacsens' auto-indent happy */
41}
42#endif
43#endif
44
45
46#if 0 /* keep Emacsens' auto-indent happy */
47{
48#endif
49#ifdef __cplusplus
50}
51#endif
52
53#endif
54
55/** @} */ /* 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/include/gnunet_transport_address_service.h b/src/include/gnunet_transport_address_service.h
new file mode 100644
index 000000000..9f0717d00
--- /dev/null
+++ b/src/include/gnunet_transport_address_service.h
@@ -0,0 +1,116 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2018 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 Christian Grothoff
23 *
24 * @file
25 * Provide addresses to transport for validation
26 *
27 * @defgroup transport TRANSPORT service
28 * Low-level communication with other peers
29 *
30 * @see [Documentation](https://gnunet.org/transport-service)
31 *
32 * @{
33 */
34
35#ifndef GNUNET_TRANSPORT_ADDRESS_SERVICE_H
36#define GNUNET_TRANSPORT_ADDRESS_SERVICE_H
37
38#ifdef __cplusplus
39extern "C"
40{
41#if 0 /* keep Emacsens' auto-indent happy */
42}
43#endif
44#endif
45
46#include "gnunet_util_lib.h"
47#include "gnunet_nt_lib.h"
48
49/**
50 * Version number of the transport address API.
51 */
52#define GNUNET_TRANSPORT_ADDRESS_VERSION 0x00000000
53
54
55/**
56 * Opaque handle to the transport service for communicators.
57 */
58struct GNUNET_TRANSPORT_AddressHandle;
59
60
61/**
62 * Connect to the transport service.
63 *
64 * @param cfg configuration to use
65 * @return NULL on error
66 */
67struct GNUNET_TRANSPORT_AddressHandle *
68GNUNET_TRANSPORT_address_connect (const struct GNUNET_CONFIGURATION_Handle *cfg);
69
70
71/**
72 * Disconnect from the transport service.
73 *
74 * @param ch handle returned from connect
75 */
76void
77GNUNET_TRANSPORT_address_disconnect (struct GNUNET_TRANSPORT_AddressHandle *ch);
78
79
80/**
81 * The client has learned about a possible address for peer @a pid
82 * (i.e. via broadcast, multicast, DHT, ...). The transport service
83 * should consider validating it. Note that the plugin is NOT expected
84 * to have verified the signature, the transport service must decide
85 * whether to check the signature.
86 *
87 * While the notification is sent to @a ch asynchronously, this API
88 * does not return a handle as the delivery of addresses is simply
89 * unreliable, and if @a ch is down, the data provided will simply be
90 * lost.
91 *
92 * @param ch communicator handle
93 * @param pid peer the address is for
94 * @param raw raw address data
95 * @param raw_size number of bytes in @a raw
96 */
97void
98GNUNET_TRANSPORT_address_try (struct GNUNET_TRANSPORT_AddressHandle *ch,
99 const struct GNUNET_PeerIdentity *pid,
100 const void *raw,
101 const size_t raw_size);
102
103
104#if 0 /* keep Emacsens' auto-indent happy */
105{
106#endif
107#ifdef __cplusplus
108}
109#endif
110
111/* ifndef GNUNET_TRANSPORT_ADDRESS_SERVICE_H */
112#endif
113
114/** @} */ /* end of group */
115
116/* end of gnunet_transport_address_service.h */
diff --git a/src/include/gnunet_transport_hello_service.h b/src/include/gnunet_transport_hello_service.h
index d568c621e..58a1e9979 100644
--- a/src/include/gnunet_transport_hello_service.h
+++ b/src/include/gnunet_transport_hello_service.h
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -107,7 +107,7 @@ enum GNUNET_TRANSPORT_AddressClass
107 * Bitmask for "any" address. 107 * Bitmask for "any" address.
108 */ 108 */
109 GNUNET_TRANSPORT_AC_ANY = 65535 109 GNUNET_TRANSPORT_AC_ANY = 65535
110 110
111}; 111};
112 112
113 113
diff --git a/src/include/platform.h b/src/include/platform.h
index 1bae7ca44..01b0bcf9e 100644
--- a/src/include/platform.h
+++ b/src/include/platform.h
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -281,4 +281,14 @@ atoll (const char *nptr);
281 */ 281 */
282#define GNUNET_TERM_SIG SIGTERM 282#define GNUNET_TERM_SIG SIGTERM
283 283
284
285#ifndef PATH_MAX
286/**
287 * Assumed maximum path length.
288 */
289#define PATH_MAX 4096
290#endif
291
292
293
284#endif 294#endif
diff --git a/src/integration-tests/confs/c_bootstrap_server.conf b/src/integration-tests/confs/c_bootstrap_server.conf
index bcfa6b212..59f2bb949 100644
--- a/src/integration-tests/confs/c_bootstrap_server.conf
+++ b/src/integration-tests/confs/c_bootstrap_server.conf
@@ -10,29 +10,25 @@ PRIVATE_KEY = hostkeys/c_bootstrap_server
10[transport] 10[transport]
11UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-transport-8 11UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-transport-8
12PORT = 20011 12PORT = 20011
13PLUGINS = tcp udp http_client https_client http_server https_server 13PLUGINS = tcp
14 14
15[transport-tcp] 15[transport-tcp]
16PORT = 20010 16PORT = 20010
17ADVERTISED_PORT = 20010 17ADVERTISED_PORT = 20010
18 18
19[transport-udp]
20PORT = 20009
21
22[transport-http_server]
23PORT = 20008
24
25[transport-https_server]
26PORT = 20007
27
28[hostlist] 19[hostlist]
29OPTIONS = -p 20OPTIONS = -p
30SERVERs = 21SERVERs =
31 22
32[nat] 23[nat]
33BEHIND_NAT = NO 24BEHIND_NAT = NO
34DISABLEV6 = NO 25DISABLEV6 = NO
26UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-nat-4
27PORT = 20070
35 28
29[nat-auto]
30UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-natauto-4
31PORT = 20076
36 32
37[arm] 33[arm]
38UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-arm-4 34UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-arm-4
@@ -94,6 +90,3 @@ PORT = 20001
94[nse] 90[nse]
95UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-nse-12 91UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-nse-12
96PORT = 20015 92PORT = 20015
97
98
99
diff --git a/src/integration-tests/confs/c_nat_client.conf b/src/integration-tests/confs/c_nat_client.conf
index 0040a8dc0..550bd38f7 100644
--- a/src/integration-tests/confs/c_nat_client.conf
+++ b/src/integration-tests/confs/c_nat_client.conf
@@ -10,7 +10,7 @@ PRIVATE_KEY = hostkeys/c_nat_client
10[transport] 10[transport]
11UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-transport-50 11UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-transport-50
12PORT = 20065 12PORT = 20065
13PLUGINS = tcp udp http_client https_client 13PLUGINS = tcp
14 14
15[transport-tcp] 15[transport-tcp]
16PORT = 0 16PORT = 0
@@ -25,7 +25,12 @@ SERVERS = http://localhost:8080/
25[nat] 25[nat]
26BEHIND_NAT = YES 26BEHIND_NAT = YES
27DISABLEV6 = NO 27DISABLEV6 = NO
28UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-nat-46
29PORT = 20071
28 30
31[nat-auto]
32UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-natauto-46
33PORT = 20077
29 34
30[arm] 35[arm]
31UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-arm-46 36UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-arm-46
diff --git a/src/integration-tests/confs/c_no_nat_client.conf b/src/integration-tests/confs/c_no_nat_client.conf
index 38a7d7fbc..4573df601 100644
--- a/src/integration-tests/confs/c_no_nat_client.conf
+++ b/src/integration-tests/confs/c_no_nat_client.conf
@@ -7,7 +7,7 @@ GNUNET_TEST_HOME = $GNUNET_TMP/c_no_nat_client/
7PRIVATE_KEY = hostkeys/c_no_nat_client 7PRIVATE_KEY = hostkeys/c_no_nat_client
8 8
9[transport] 9[transport]
10PLUGINS = tcp udp http_client https_client 10PLUGINS = tcp
11UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-transport-22 11UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-transport-22
12PORT = 20029 12PORT = 20029
13 13
@@ -15,17 +15,18 @@ PORT = 20029
15PORT = 20028 15PORT = 20028
16ADVERTISED_PORT = 20028 16ADVERTISED_PORT = 20028
17 17
18[transport-udp]
19PORT = 20027
20BROADCAST_INTERVAL = 30 s
21
22[hostlist] 18[hostlist]
23SERVERS = http://localhost:8080/ 19SERVERS = http://localhost:8080/
24 20
25[nat] 21[nat]
26BEHIND_NAT = NO 22BEHIND_NAT = NO
27DISABLEV6 = NO 23DISABLEV6 = NO
24UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-nat-18
25PORT = 20072
28 26
27[nat-auto]
28UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-natauto-18
29PORT = 20074
29 30
30[arm] 31[arm]
31UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-arm-18 32UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-arm-18
diff --git a/src/integration-tests/confs/c_no_nat_client_2.conf b/src/integration-tests/confs/c_no_nat_client_2.conf
index 6c8f07632..a7d9a436f 100644
--- a/src/integration-tests/confs/c_no_nat_client_2.conf
+++ b/src/integration-tests/confs/c_no_nat_client_2.conf
@@ -8,7 +8,7 @@ PRIVATE_KEY = hostkeys/c_no_nat_client_2
8 8
9 9
10[transport] 10[transport]
11PLUGINS = tcp udp http_client https_client 11PLUGINS = tcp
12UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-transport-22 12UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-transport-22
13PORT = 20039 13PORT = 20039
14 14
@@ -26,6 +26,12 @@ SERVERS = http://localhost:8080/
26[nat] 26[nat]
27BEHIND_NAT = NO 27BEHIND_NAT = NO
28DISABLEV6 = NO 28DISABLEV6 = NO
29PORT = 20073
30UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-nat-18
31
32[nat-auto]
33PORT = 20075
34UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-natauto-18
29 35
30 36
31[arm] 37[arm]
@@ -111,5 +117,3 @@ PORT = 20038
111[dv] 117[dv]
112UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-dv-36 118UNIXPATH = $GNUNET_RUNTIME_DIR/test-service-dv-36
113PORT = 20039 119PORT = 20039
114
115
diff --git a/src/integration-tests/gnunet_pyexpect.py.in b/src/integration-tests/gnunet_pyexpect.py.in
index 73be6f295..83acb908f 100644
--- a/src/integration-tests/gnunet_pyexpect.py.in
+++ b/src/integration-tests/gnunet_pyexpect.py.in
@@ -19,6 +19,7 @@
19# 19#
20# Testcase for gnunet-peerinfo 20# Testcase for gnunet-peerinfo
21from __future__ import print_function 21from __future__ import print_function
22from builtins import object
22import os 23import os
23import re 24import re
24import subprocess 25import subprocess
diff --git a/src/integration-tests/gnunet_testing.py.in b/src/integration-tests/gnunet_testing.py.in
index 0d02a792f..c9342ecf0 100644
--- a/src/integration-tests/gnunet_testing.py.in
+++ b/src/integration-tests/gnunet_testing.py.in
@@ -11,22 +11,34 @@
11# WITHOUT ANY WARRANTY; without even the implied warranty of 11# WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# Affero General Public License for more details. 13# Affero General Public License for more details.
14# 14#
15# You should have received a copy of the GNU Affero General Public License 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/>. 16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17# 17#
18# SPDX-License-Identifier: AGPL3.0-or-later 18# SPDX-License-Identifier: AGPL3.0-or-later
19# 19#
20# Functions for integration testing 20# Functions for integration testing
21from __future__ import unicode_literals
22from __future__ import print_function
23from builtins import object
24from builtins import str
21import os 25import os
22import subprocess 26import subprocess
23import sys 27import sys
24import shutil 28import shutil
25import time 29import time
26from gnunet_pyexpect import pexpect 30from gnunet_pyexpect import pexpect
31import logging
27 32
33logger = logging.getLogger()
34handler = logging.StreamHandler()
35formatter = logging.Formatter(
36 '%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
37handler.setFormatter(formatter)
38logger.addHandler(handler)
39logger.setLevel(logging.DEBUG)
28 40
29class Check: 41class Check(object):
30 def __init__(self, test): 42 def __init__(self, test):
31 self.fulfilled = False 43 self.fulfilled = False
32 self.conditions = list() 44 self.conditions = list()
@@ -55,7 +67,7 @@ class Check:
55 time.sleep(1) 67 time.sleep(1)
56 execs += 1 68 execs += 1
57 if ((False == res) and (execs >= timeout)): 69 if ((False == res) and (execs >= timeout)):
58 print(('Check had timeout after ' + str(timeout) + ' seconds')) 70 logger.debug('Check had timeout after %s seconds', str(timeout))
59 neg_cont(self) 71 neg_cont(self)
60 elif ((False == res) and (execs < timeout)): 72 elif ((False == res) and (execs < timeout)):
61 if (None != neg_cont): 73 if (None != neg_cont):
@@ -83,7 +95,7 @@ class Check:
83 neg += 1 95 neg += 1
84 else: 96 else:
85 pos += 1 97 pos += 1
86 print((str(pos) + ' out of ' + str(pos+neg) + ' conditions fulfilled')) 98 logger.debug('%s out of %s conditions fulfilled', str(pos), str(pos+neg))
87 return self.fulfilled 99 return self.fulfilled
88 100
89 def reset(self): 101 def reset(self):
@@ -92,7 +104,7 @@ class Check:
92 c.fulfilled = False 104 c.fulfilled = False
93 105
94 106
95class Condition: 107class Condition(object):
96 def __init__(self): 108 def __init__(self):
97 self.fulfilled = False 109 self.fulfilled = False
98 self.type = 'generic' 110 self.type = 'generic'
@@ -106,9 +118,9 @@ class Condition:
106 118
107 def evaluate(self, failed_only): 119 def evaluate(self, failed_only):
108 if ((self.fulfilled == False) and (failed_only == True)): 120 if ((self.fulfilled == False) and (failed_only == True)):
109 print(str(self.type) + 'condition for was ' + str(self.fulfilled)) 121 logger.debug('%s condition for was %s', str(self.type), str(self.fulfilled))
110 elif (failed_only == False): 122 elif (failed_only == False):
111 print(str(self.type) + 'condition for was ' + str(self.fulfilled)) 123 logger.debug('%s condition for was %s', str(self.type), str(self.fulfilled))
112 return self.fulfilled 124 return self.fulfilled
113 125
114 126
@@ -131,26 +143,26 @@ class FileExistCondition(Condition):
131 143
132 def evaluate(self, failed_only): 144 def evaluate(self, failed_only):
133 if ((self.fulfilled == False) and (failed_only == True)): 145 if ((self.fulfilled == False) and (failed_only == True)):
134 print(str(self.type) + 'condition for file '+self.file+' was ' + str(self.fulfilled)) 146 logger.debug('%s confition for file %s was %s', str(self.type), self.file, str(self.fulfilled))
135 elif (failed_only == False): 147 elif (failed_only == False):
136 print(str(self.type) + 'condition for file '+self.file+' was ' + str(self.fulfilled)) 148 logger.debug('%s confition for file %s was %s', str(self.type), self.file, str(self.fulfilled))
137 return self.fulfilled 149 return self.fulfilled
138 150
139 151
140class StatisticsCondition (Condition): 152class StatisticsCondition(Condition):
141 def __init__(self, peer, subsystem, name, value): 153 def __init__(self, peer, subsystem, name, value):
142 self.fulfilled = False 154 self.fulfilled = False
143 self.type = 'statistics' 155 self.type = 'statistics'
144 self.peer = peer 156 self.peer = peer
145 self.subsystem = subsystem 157 self.subsystem = subsystem
146 self.name = name 158 self.name = name
147 self.value = value 159 self.value = str(value)
148 self.result = -1 160 self.result = -1
149 161
150 def check(self): 162 def check(self):
151 if (self.fulfilled == False): 163 if (self.fulfilled == False):
152 self.result = self.peer.get_statistics_value(self.subsystem, self.name) 164 self.result = self.peer.get_statistics_value(self.subsystem, self.name)
153 if (str(self.result) == str(self.value)): 165 if (self.result == self.value):
154 self.fulfilled = True 166 self.fulfilled = True
155 return True 167 return True
156 else: 168 else:
@@ -159,10 +171,6 @@ class StatisticsCondition (Condition):
159 return True 171 return True
160 172
161 def evaluate(self, failed_only): 173 def evaluate(self, failed_only):
162 if (self.result == -1):
163 res = 'NaN'
164 else:
165 res = str(self.result)
166 if (self.fulfilled == False): 174 if (self.fulfilled == False):
167 fail = " FAIL!" 175 fail = " FAIL!"
168 op = " != " 176 op = " != "
@@ -170,12 +178,12 @@ class StatisticsCondition (Condition):
170 fail = "" 178 fail = ""
171 op = " == " 179 op = " == "
172 if (((self.fulfilled == False) and (failed_only == True)) or (failed_only == False)): 180 if (((self.fulfilled == False) and (failed_only == True)) or (failed_only == False)):
173 print(self.peer.id[:4] + " " + self.peer.cfg + " " + str(self.type) + ' condition in subsystem "' + self.subsystem.ljust(12) + '" : "' + self.name.ljust(30) + '" : (expected/real value) ' + str(self.value) + op + res + fail) 181 logger.debug('%s %s condition in subsystem %s: %s: (expected/real value) %s %s %s %s', self.peer.id[:4].decode("utf-8"), self.peer.cfg, self.subsystem.ljust(12), self.name.ljust(30), self.value, op, self.result, fail)
174 return self.fulfilled 182 return self.fulfilled
175 183
176 184
177# Specify two statistic values and check if they are equal 185# Specify two statistic values and check if they are equal
178class EqualStatisticsCondition (Condition): 186class EqualStatisticsCondition(Condition):
179 def __init__(self, peer, subsystem, name, peer2, subsystem2, name2): 187 def __init__(self, peer, subsystem, name, peer2, subsystem2, name2):
180 self.fulfilled = False 188 self.fulfilled = False
181 self.type = 'equalstatistics' 189 self.type = 'equalstatistics'
@@ -192,7 +200,7 @@ class EqualStatisticsCondition (Condition):
192 if (self.fulfilled == False): 200 if (self.fulfilled == False):
193 self.result = self.peer.get_statistics_value(self.subsystem, self.name) 201 self.result = self.peer.get_statistics_value(self.subsystem, self.name)
194 self.result2 = self.peer2.get_statistics_value(self.subsystem2, self.name2) 202 self.result2 = self.peer2.get_statistics_value(self.subsystem2, self.name2)
195 if (str(self.result) == str(self.result2)): 203 if (self.result == self.result2):
196 self.fulfilled = True 204 self.fulfilled = True
197 return True 205 return True
198 else: 206 else:
@@ -201,26 +209,12 @@ class EqualStatisticsCondition (Condition):
201 return True 209 return True
202 210
203 def evaluate(self, failed_only): 211 def evaluate(self, failed_only):
204 if (self.result == -1):
205 res = 'NaN'
206 else:
207 res = str(self.result)
208 if (self.result2 == -1):
209 res2 = 'NaN'
210 else:
211 res2 = str(self.result2)
212 if (self.fulfilled == False):
213 fail = " FAIL!"
214 op = " != "
215 else:
216 fail = ""
217 op = " == "
218 if (((self.fulfilled == False) and (failed_only == True)) or (failed_only == False)): 212 if (((self.fulfilled == False) and (failed_only == True)) or (failed_only == False)):
219 print(self.peer.id[:4] + ' "' + self.subsystem.ljust(12) + '" "' + self.name.ljust(30) + '" == ' + str(self.result) + " " + self.peer2.id[:4] + ' "' + self.subsystem2.ljust(12) + '" ' + self.name2.ljust(30) + '" ' + str(self.result2)) 213 logger.debug('%s %s %s == %s %s %s %s %s', self.peer.id[:4], self.subsystem.ljust(12), self.name.ljust(30), self.result, self.peer2.id[:4], self.subsystem2.ljust(12), self.name2.ljust(30), self.result2)
220 return self.fulfilled 214 return self.fulfilled
221 215
222 216
223class Test: 217class Test(object):
224 def __init__(self, testname, verbose): 218 def __init__(self, testname, verbose):
225 self.peers = list() 219 self.peers = list()
226 self.verbose = verbose 220 self.verbose = verbose
@@ -252,10 +246,11 @@ class Test:
252 print(msg) 246 print(msg)
253 247
254 248
255class Peer: 249class Peer(object):
256 def __init__(self, test, cfg_file): 250 def __init__(self, test, cfg_file):
257 if (False == os.path.isfile(cfg_file)): 251 if (False == os.path.isfile(cfg_file)):
258 print(("Peer cfg " + cfg_file + ": FILE NOT FOUND")) 252 # print(("Peer cfg " + cfg_file + ": FILE NOT FOUND"))
253 logger.debug('Peer cfg %s : FILE NOT FOUND', cfg_file)
259 self.id = "<NaN>" 254 self.id = "<NaN>"
260 self.test = test 255 self.test = test
261 self.started = False 256 self.started = False
@@ -263,22 +258,30 @@ class Peer:
263 258
264 def __del__(self): 259 def __del__(self):
265 if (self.started == True): 260 if (self.started == True):
266 print('ERROR! Peer using cfg ' + self.cfg + ' was not stopped') 261 # print('ERROR! Peer using cfg ' + self.cfg + ' was not stopped')
262 logger.debug('ERROR! Peer using cfg %s was not stopped', self.cfg)
267 ret = self.stop() 263 ret = self.stop()
268 if (False == ret): 264 if (False == ret):
269 print('ERROR! Peer using cfg ' + self.cfg + ' could not be stopped') 265 # print('ERROR! Peer using cfg ' +
266 # self.cfg +
267 # ' could not be stopped')
268 logger.debug('ERROR! Peer using cfg %s could not be stopped', self.cfg)
270 self.started = False 269 self.started = False
271 return ret 270 return ret
272 else: 271 else:
273 return False 272 return False
274 273
275 def start(self): 274 def start(self):
275 os.unsetenv ("XDG_CONFIG_HOME")
276 os.unsetenv ("XDG_DATA_HOME")
277 os.unsetenv ("XDG_CACHE_HOME")
276 self.test.p("Starting peer using cfg " + self.cfg) 278 self.test.p("Starting peer using cfg " + self.cfg)
277 try: 279 try:
278 server = subprocess.Popen([self.test.gnunetarm, '-sq', '-c', self.cfg]) 280 server = subprocess.Popen([self.test.gnunetarm, '-sq', '-c', self.cfg])
279 server.communicate() 281 server.communicate()
280 except OSError: 282 except OSError:
281 print("Can not start peer") 283 # print("Can not start peer")
284 logger.debug('Can not start peer')
282 self.started = False 285 self.started = False
283 return False 286 return False
284 self.started = True 287 self.started = True
@@ -288,9 +291,10 @@ class Peer:
288 server.spawn(None, [self.test.gnunetpeerinfo, '-c', self.cfg, '-s'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 291 server.spawn(None, [self.test.gnunetpeerinfo, '-c', self.cfg, '-s'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
289 test = server.read("stdout", 1024) 292 test = server.read("stdout", 1024)
290 except OSError: 293 except OSError:
291 print("Can not get peer identity") 294 # print("Can not get peer identity")
292 test = (test.split('`')[1]) 295 logger.debug('Can not get peer identity')
293 self.id = test.split('\'')[0] 296 test = (test.split(b'`')[1])
297 self.id = test.split(b'\'')[0]
294 return True 298 return True
295 299
296 def stop(self): 300 def stop(self):
@@ -301,7 +305,8 @@ class Peer:
301 server = subprocess.Popen([self.test.gnunetarm, '-eq', '-c', self.cfg]) 305 server = subprocess.Popen([self.test.gnunetarm, '-eq', '-c', self.cfg])
302 server.communicate() 306 server.communicate()
303 except OSError: 307 except OSError:
304 print("Can not stop peer") 308 # print("Can not stop peer")
309 logger.debug('Can not stop peer')
305 return False 310 return False
306 self.started = False 311 self.started = False
307 return True 312 return True
@@ -311,12 +316,15 @@ class Peer:
311 server.spawn(None, [self.test.gnunetstatistics, '-c', self.cfg, '-q', '-n', name, '-s', subsystem], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 316 server.spawn(None, [self.test.gnunetstatistics, '-c', self.cfg, '-q', '-n', name, '-s', subsystem], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
312 # server.expect ("stdout", re.compile (r"")) 317 # server.expect ("stdout", re.compile (r""))
313 test = server.read("stdout", 10240) 318 test = server.read("stdout", 10240)
314 tests = test.partition('\n') 319 tests = test.partition(b'\n')
315 # On W32 GNUnet outputs with \r\n, rather than \n 320 # On W32 GNUnet outputs with \r\n, rather than \n
316 if os.name == 'nt' and tests[1] == '\n' and tests[0][-1] == '\r': 321 if os.name == 'nt' and tests[1] == b'\n' and tests[0][-1] == b'\r':
317 tests = (tests[0][:-1], tests[1], tests[2]) 322 tests = (tests[0][:-1], tests[1], tests[2])
318 tests = tests[0] 323 tests = tests[0]
319 if (tests.isdigit() == True): 324 result = tests.decode("utf-8").strip()
320 return tests 325 logger.debug('running gnunet-statistics %s for %s "/" %s yields %s', self.cfg, name, subsystem, result)
326 if (result.isdigit() == True):
327 return result
321 else: 328 else:
329 logger.debug('Invalid statistics value: %s is not a number!', result)
322 return -1 330 return -1
diff --git a/src/integration-tests/test_integration_bootstrap_and_connect.py.in b/src/integration-tests/test_integration_bootstrap_and_connect.py.in
index 5bd938019..f0de1c0cd 100755
--- a/src/integration-tests/test_integration_bootstrap_and_connect.py.in
+++ b/src/integration-tests/test_integration_bootstrap_and_connect.py.in
@@ -11,13 +11,14 @@
11# WITHOUT ANY WARRANTY; without even the implied warranty of 11# WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# Affero General Public License for more details. 13# Affero General Public License for more details.
14# 14#
15# You should have received a copy of the GNU Affero General Public License 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/>. 16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17# 17#
18# SPDX-License-Identifier: AGPL3.0-or-later 18# SPDX-License-Identifier: AGPL3.0-or-later
19# 19#
20# 20#
21from __future__ import print_function
21import signal 22import signal
22import sys 23import sys
23import os 24import os
diff --git a/src/integration-tests/test_integration_clique.py.in b/src/integration-tests/test_integration_clique.py.in
index 0444cf249..b5d6dd518 100755
--- a/src/integration-tests/test_integration_clique.py.in
+++ b/src/integration-tests/test_integration_clique.py.in
@@ -25,6 +25,7 @@
25# Conditions for successful exit: 25# Conditions for successful exit:
26# Both peers have 2 connected peers in transport, core, topology, fs and dht 26# Both peers have 2 connected peers in transport, core, topology, fs and dht
27 27
28from __future__ import print_function
28import sys 29import sys
29import signal 30import signal
30import os 31import os
diff --git a/src/integration-tests/test_integration_disconnect.py.in b/src/integration-tests/test_integration_disconnect.py.in
index f8b411778..a81c78540 100755
--- a/src/integration-tests/test_integration_disconnect.py.in
+++ b/src/integration-tests/test_integration_disconnect.py.in
@@ -11,13 +11,14 @@
11# WITHOUT ANY WARRANTY; without even the implied warranty of 11# WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# Affero General Public License for more details. 13# Affero General Public License for more details.
14# 14#
15# You should have received a copy of the GNU Affero General Public License 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/>. 16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17# 17#
18# SPDX-License-Identifier: AGPL3.0-or-later 18# SPDX-License-Identifier: AGPL3.0-or-later
19# 19#
20# 20#
21from __future__ import print_function
21import sys 22import sys
22import signal 23import signal
23import os 24import os
@@ -29,8 +30,8 @@ from gnunet_testing import Peer
29from gnunet_testing import Test 30from gnunet_testing import Test
30from gnunet_testing import Check 31from gnunet_testing import Check
31from gnunet_testing import Condition 32from gnunet_testing import Condition
32from gnunet_testing import * 33from gnunet_testing import *
33 34
34 35
35# 36#
36# This test tests if a fresh peer bootstraps from a hostlist server and then 37# This test tests if a fresh peer bootstraps from a hostlist server and then
@@ -71,16 +72,16 @@ def cleanup ():
71 72
72def success_disconnect_cont (check): 73def success_disconnect_cont (check):
73 print('Peers disconnected successfully') 74 print('Peers disconnected successfully')
74 global success 75 global success
75 success = True; 76 success = True;
76 77
77 78
78def fail_disconnect_cont (check): 79def fail_disconnect_cont (check):
79 global success 80 global success
80 success = False; 81 success = False;
81 print('Peers failed to disconnect') 82 print('Peers failed to disconnect')
82 check.evaluate(True) 83 check.evaluate(True)
83 84
84def check_disconnect (): 85def check_disconnect ():
85 test.p ('Shutting down bootstrap server') 86 test.p ('Shutting down bootstrap server')
86 server.stop () 87 server.stop ()
@@ -98,8 +99,8 @@ def success_connect_cont (check):
98 check_disconnect () 99 check_disconnect ()
99 100
100 101
101def fail_connect_cont (check): 102def fail_connect_cont (check):
102 global success 103 global success
103 success= False 104 success= False
104 print('Peers failed to connected!') 105 print('Peers failed to connected!')
105 check.evaluate(True) 106 check.evaluate(True)
@@ -107,33 +108,33 @@ def fail_connect_cont (check):
107 108
108def check_connect (): 109def check_connect ():
109 check = Check (test) 110 check = Check (test)
111 check.add (StatisticsCondition (server, 'transport', '# peers connected',1))
112 check.add (StatisticsCondition (server, 'core', '# peers connected',1))
113 check.add (StatisticsCondition (server, 'topology', '# peers connected',1))
114 check.add (StatisticsCondition (server, 'dht', '# peers connected',1))
115 check.add (StatisticsCondition (server, 'fs', '# peers connected',1))
116
110 check.add (StatisticsCondition (client, 'transport', '# peers connected',1)) 117 check.add (StatisticsCondition (client, 'transport', '# peers connected',1))
111 check.add (StatisticsCondition (client, 'core', '# peers connected',1)) 118 check.add (StatisticsCondition (client, 'core', '# peers connected',1))
112 check.add (StatisticsCondition (client, 'topology', '# peers connected',1)) 119 check.add (StatisticsCondition (client, 'topology', '# peers connected',1))
113 check.add (StatisticsCondition (client, 'dht', '# peers connected',1)) 120 check.add (StatisticsCondition (client, 'dht', '# peers connected',1))
114 check.add (StatisticsCondition (client, 'fs', '# peers connected',1)) 121 check.add (StatisticsCondition (client, 'fs', '# peers connected',1))
115 122
116 check.add (StatisticsCondition (server, 'transport', '# peers connected',1))
117 check.add (StatisticsCondition (server, 'core', '# peers connected',1))
118 check.add (StatisticsCondition (server, 'topology', '# peers connected',1))
119 check.add (StatisticsCondition (server, 'dht', '# peers connected',1))
120 check.add (StatisticsCondition (server, 'fs', '# peers connected',1))
121
122 check.run_blocking (check_timeout, success_connect_cont, fail_connect_cont) 123 check.run_blocking (check_timeout, success_connect_cont, fail_connect_cont)
123 124
124# 125#
125# Test execution 126# Test execution
126# 127#
127 128
128def SigHandler(signum = None, frame = None): 129def SigHandler(signum = None, frame = None):
129 global success 130 global success
130 global server 131 global server
131 global client 132 global client
132 133
133 print('Test was aborted!') 134 print('Test was aborted!')
134 if (None != server): 135 if (None != server):
135 server.stop () 136 server.stop ()
136 if (None != client): 137 if (None != client):
137 client.stop () 138 client.stop ()
138 cleanup () 139 cleanup ()
139 sys.exit(success) 140 sys.exit(success)
@@ -142,67 +143,63 @@ def run ():
142 global success 143 global success
143 global test 144 global test
144 global server 145 global server
145 global client 146 global client
146 147
147 server = None 148 server = None
148 client = None 149 client = None
149 success = False 150 success = False
150 151
151 for sig in signals: 152 for sig in signals:
152 signal.signal(sig, SigHandler) 153 signal.signal(sig, SigHandler)
153 154
154 test = Test ('test_integration_bootstrap_and_connect.py', verbose) 155 test = Test ('test_integration_bootstrap_and_connect.py', verbose)
155 cleanup () 156 cleanup ()
156 157
157 server = Peer(test, './confs/c_bootstrap_server.conf'); 158 server = Peer(test, './confs/c_bootstrap_server.conf');
158 client = Peer(test, './confs/c_no_nat_client.conf'); 159 client = Peer(test, './confs/c_no_nat_client.conf');
159 160
160 if (True != server.start()): 161 if (True != server.start()):
161 print('Failed to start server') 162 print('Failed to start server')
162 if (None != server): 163 if (None != server):
163 server.stop () 164 server.stop ()
164 cleanup () 165 cleanup ()
165 sys.exit(success) 166 sys.exit(success)
166 167
167 # Give the server time to start 168 # Give the server time to start
168 time.sleep(5) 169 time.sleep(5)
169 170
170 if (True != client.start()): 171 if (True != client.start()):
171 print('Failed to start client') 172 print('Failed to start client')
172 if (None != server): 173 if (None != server):
173 server.stop () 174 server.stop ()
174 if (None != client): 175 if (None != client):
175 client.stop () 176 client.stop ()
176 cleanup () 177 cleanup ()
177 sys.exit(success) 178 sys.exit(success)
178 179
179 if ((client.started == True) and (server.started == True)): 180 if ((client.started == True) and (server.started == True)):
180 test.p ('Peers started, running check') 181 test.p ('Peers started, running check')
181 time.sleep(5) 182 time.sleep(5)
182 check_connect () 183 check_connect ()
183 server.stop () 184 server.stop ()
184 client.stop () 185 client.stop ()
185 186
186 cleanup () 187 cleanup ()
187 188
188 if (success == False): 189 if (success == False):
189 print ('Test failed') 190 print ('Test failed')
190 return False 191 return False
191 else: 192 else:
192 return True 193 return True
193 194
194try: 195try:
195 run () 196 run ()
196except (KeyboardInterrupt, SystemExit): 197except (KeyboardInterrupt, SystemExit):
197 print('Test interrupted') 198 print('Test interrupted')
198 server.stop () 199 server.stop ()
199 client.stop () 200 client.stop ()
200 cleanup () 201 cleanup ()
201if (success == False): 202if (success == False):
202 sys.exit(1) 203 sys.exit(1)
203else: 204else:
204 sys.exit(0) 205 sys.exit(0)
205
206
207
208
diff --git a/src/integration-tests/test_integration_disconnect_nat.py.in b/src/integration-tests/test_integration_disconnect_nat.py.in
index 885492741..601586f47 100755
--- a/src/integration-tests/test_integration_disconnect_nat.py.in
+++ b/src/integration-tests/test_integration_disconnect_nat.py.in
@@ -11,13 +11,14 @@
11# WITHOUT ANY WARRANTY; without even the implied warranty of 11# WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# Affero General Public License for more details. 13# Affero General Public License for more details.
14# 14#
15# You should have received a copy of the GNU Affero General Public License 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/>. 16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17# 17#
18# SPDX-License-Identifier: AGPL3.0-or-later 18# SPDX-License-Identifier: AGPL3.0-or-later
19# 19#
20# 20#
21from __future__ import print_function
21import sys 22import sys
22import signal 23import signal
23import os 24import os
diff --git a/src/integration-tests/test_integration_reconnect.py.in b/src/integration-tests/test_integration_reconnect.py.in
index 13179eef6..e8abacd48 100755
--- a/src/integration-tests/test_integration_reconnect.py.in
+++ b/src/integration-tests/test_integration_reconnect.py.in
@@ -11,13 +11,14 @@
11# WITHOUT ANY WARRANTY; without even the implied warranty of 11# WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# Affero General Public License for more details. 13# Affero General Public License for more details.
14# 14#
15# You should have received a copy of the GNU Affero General Public License 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/>. 16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17# 17#
18# SPDX-License-Identifier: AGPL3.0-or-later 18# SPDX-License-Identifier: AGPL3.0-or-later
19# 19#
20# 20#
21from __future__ import print_function
21import sys 22import sys
22import os 23import os
23import subprocess 24import subprocess
@@ -29,13 +30,13 @@ from gnunet_testing import Peer
29from gnunet_testing import Test 30from gnunet_testing import Test
30from gnunet_testing import Check 31from gnunet_testing import Check
31from gnunet_testing import Condition 32from gnunet_testing import Condition
32from gnunet_testing import * 33from gnunet_testing import *
33 34
34 35
35# 36#
36# This test tests if a fresh peer bootstraps from a hostlist server and then 37# This test tests if a fresh peer bootstraps from a hostlist server and then
37# successfully connects to the server. When both peers are connected 38# successfully connects to the server. When both peers are connected
38# in transport, core, topology, fs, botth peers are shutdown and restarted 39# in transport, core, topology, fs, botth peers are shutdown and restarted
39# 40#
40# Conditions for successful exit: 41# Conditions for successful exit:
41# Both peers have 1 connected peer in transport, core, topology, fs after restart 42# Both peers have 1 connected peer in transport, core, topology, fs after restart
@@ -67,68 +68,68 @@ def cleanup_onerror (function, path, excinfo):
67 68
68def cleanup (): 69def cleanup ():
69 retries = 10 70 retries = 10
70 path = os.path.join (tmp, "c_bootstrap_server") 71 path = os.path.join (tmp, "c_bootstrap_server")
71 test.p ("Removing " + path) 72 test.p ("Removing " + path)
72 while ((os.path.exists(path)) and (retries > 0)): 73 while ((os.path.exists(path)) and (retries > 0)):
73 shutil.rmtree ((path), False, cleanup_onerror) 74 shutil.rmtree ((path), False, cleanup_onerror)
74 time.sleep (1) 75 time.sleep (1)
75 retries -= 1 76 retries -= 1
76 if (os.path.exists(path)): 77 if (os.path.exists(path)):
77 test.p ("Failed to remove " + path) 78 test.p ("Failed to remove " + path)
78 79
79 80
80 retries = 10 81 retries = 10
81 path = os.path.join (tmp, "c_no_nat_client") 82 path = os.path.join (tmp, "c_no_nat_client")
82 test.p ("Removing " + path) 83 test.p ("Removing " + path)
83 while ((os.path.exists(path)) and (retries > 0)): 84 while ((os.path.exists(path)) and (retries > 0)):
84 shutil.rmtree ((path), False, cleanup_onerror) 85 shutil.rmtree ((path), False, cleanup_onerror)
85 time.sleep (1) 86 time.sleep (1)
86 retries -= 1 87 retries -= 1
87 if (os.path.exists(path)): 88 if (os.path.exists(path)):
88 test.p ("Failed to remove " + path) 89 test.p ("Failed to remove " + path)
89 90
90def success_restart_cont (check): 91def success_restart_cont (check):
91 global success 92 global success
92 print('Peers connected successfully after restart') 93 print('Peers connected successfully after restart')
93 server.stop () 94 server.stop ()
94 client.stop () 95 client.stop ()
95 success = True; 96 success = True;
96 97
97 98
98def fail_restart_cont (check): 99def fail_restart_cont (check):
99 global success 100 global success
100 success = False; 101 success = False;
101 print('Peers failed to connect after restart') 102 print('Peers failed to connect after restart')
102 check.evaluate(True) 103 check.evaluate(True)
103 104
104 105
105def success_connect_cont (check): 106def success_connect_cont (check):
106 print('Peers connected successfully') 107 print('Peers connected successfully')
107 server.stop () 108 server.stop ()
108 client.stop () 109 client.stop ()
109 110
110 time.sleep(5) 111 time.sleep(5)
111 112
112 test.p ('Restarting client & server') 113 test.p ('Restarting client & server')
113 server.start () 114 server.start ()
114 client.start () 115 client.start ()
115 116
116 check = Check (test) 117 check = Check (test)
117 check.add (StatisticsCondition (client, 'transport', '# peers connected',1)) 118 check.add (StatisticsCondition (client, 'transport', '# peers connected',1))
118 check.add (StatisticsCondition (client, 'core', '# peers connected',1)) 119 check.add (StatisticsCondition (client, 'core', '# peers connected',1))
119 check.add (StatisticsCondition (client, 'topology', '# peers connected',1)) 120 check.add (StatisticsCondition (client, 'topology', '# peers connected',1))
120 check.add (StatisticsCondition (client, 'fs', '# peers connected',1)) 121 check.add (StatisticsCondition (client, 'fs', '# peers connected',1))
121 122
122 check.add (StatisticsCondition (server, 'transport', '# peers connected',1)) 123 check.add (StatisticsCondition (server, 'transport', '# peers connected',1))
123 check.add (StatisticsCondition (server, 'core', '# peers connected',1)) 124 check.add (StatisticsCondition (server, 'core', '# peers connected',1))
124 check.add (StatisticsCondition (server, 'topology', '# peers connected',1)) 125 check.add (StatisticsCondition (server, 'topology', '# peers connected',1))
125 check.add (StatisticsCondition (server, 'fs', '# peers connected',1)) 126 check.add (StatisticsCondition (server, 'fs', '# peers connected',1))
126 127
127 check.run_blocking (check_timeout, success_restart_cont, fail_restart_cont) 128 check.run_blocking (check_timeout, success_restart_cont, fail_restart_cont)
128 129
129 130
130def fail_connect_cont (check): 131def fail_connect_cont (check):
131 global success 132 global success
132 success= False; 133 success= False;
133 print('Peers failed to connect') 134 print('Peers failed to connect')
134 check.evaluate(True) 135 check.evaluate(True)
@@ -140,28 +141,28 @@ def check_connect ():
140 check.add (StatisticsCondition (client, 'core', '# peers connected',1)) 141 check.add (StatisticsCondition (client, 'core', '# peers connected',1))
141 check.add (StatisticsCondition (client, 'topology', '# peers connected',1)) 142 check.add (StatisticsCondition (client, 'topology', '# peers connected',1))
142 check.add (StatisticsCondition (client, 'fs', '# peers connected',1)) 143 check.add (StatisticsCondition (client, 'fs', '# peers connected',1))
143 144
144 check.add (StatisticsCondition (server, 'transport', '# peers connected',1)) 145 check.add (StatisticsCondition (server, 'transport', '# peers connected',1))
145 check.add (StatisticsCondition (server, 'core', '# peers connected',1)) 146 check.add (StatisticsCondition (server, 'core', '# peers connected',1))
146 check.add (StatisticsCondition (server, 'topology', '# peers connected',1)) 147 check.add (StatisticsCondition (server, 'topology', '# peers connected',1))
147 check.add (StatisticsCondition (server, 'fs', '# peers connected',1)) 148 check.add (StatisticsCondition (server, 'fs', '# peers connected',1))
148 149
149 check.run_blocking (check_timeout, success_connect_cont, fail_connect_cont) 150 check.run_blocking (check_timeout, success_connect_cont, fail_connect_cont)
150 151
151# 152#
152# Test execution 153# Test execution
153# 154#
154 155
155 156
156def SigHandler(signum = None, frame = None): 157def SigHandler(signum = None, frame = None):
157 global success 158 global success
158 global server 159 global server
159 global client 160 global client
160 161
161 print('Test was aborted!') 162 print('Test was aborted!')
162 if (None != server): 163 if (None != server):
163 server.stop () 164 server.stop ()
164 if (None != client): 165 if (None != client):
165 client.stop () 166 client.stop ()
166 cleanup () 167 cleanup ()
167 sys.exit(success) 168 sys.exit(success)
@@ -171,68 +172,66 @@ def run ():
171 global test 172 global test
172 global server 173 global server
173 global client 174 global client
174 175
175 success = False 176 success = False
176 server = None 177 server = None
177 client = None 178 client = None
178 179
179 for sig in signals: 180 for sig in signals:
180 signal.signal(sig, SigHandler) 181 signal.signal(sig, SigHandler)
181 182
182 183
183 test = Test ('test_integration_disconnect', verbose) 184 test = Test ('test_integration_disconnect', verbose)
184 cleanup () 185 cleanup ()
185 server = Peer(test, './confs/c_bootstrap_server.conf'); 186 server = Peer(test, './confs/c_bootstrap_server.conf');
186 server.start(); 187 server.start();
187 188
188 client = Peer(test, './confs/c_no_nat_client.conf'); 189 client = Peer(test, './confs/c_no_nat_client.conf');
189 client.start(); 190 client.start();
190 191
191 192
192 if (True != server.start()): 193 if (True != server.start()):
193 print('Failed to start server') 194 print('Failed to start server')
194 if (None != server): 195 if (None != server):
195 server.stop () 196 server.stop ()
196 if (None != server): 197 if (None != server):
197 client.stop () 198 client.stop ()
198 cleanup () 199 cleanup ()
199 sys.exit(success) 200 sys.exit(success)
200 201
201 # Give the server time to start 202 # Give the server time to start
202 time.sleep(5) 203 time.sleep(5)
203 204
204 if (True != client.start()): 205 if (True != client.start()):
205 print('Failed to start client') 206 print('Failed to start client')
206 if (None != server): 207 if (None != server):
207 server.stop () 208 server.stop ()
208 if (None != server): 209 if (None != server):
209 client.stop () 210 client.stop ()
210 cleanup () 211 cleanup ()
211 sys.exit(success) 212 sys.exit(success)
212 213
213 check_connect () 214 check_connect ()
214 215
215 server.stop () 216 server.stop ()
216 client.stop () 217 client.stop ()
217 cleanup () 218 cleanup ()
218 219
219 if (success == False): 220 if (success == False):
220 print ('Test failed') 221 print ('Test failed')
221 return True 222 return True
222 else: 223 else:
223 return False 224 return False
224 225
225 226
226try: 227try:
227 run () 228 run ()
228except (KeyboardInterrupt, SystemExit): 229except (KeyboardInterrupt, SystemExit):
229 print('Test interrupted') 230 print('Test interrupted')
230 server.stop () 231 server.stop ()
231 client.stop () 232 client.stop ()
232 cleanup () 233 cleanup ()
233if (success == False): 234if (success == False):
234 sys.exit(1) 235 sys.exit(1)
235else: 236else:
236 sys.exit(0) 237 sys.exit(0)
237
238
diff --git a/src/integration-tests/test_integration_reconnect_nat.py.in b/src/integration-tests/test_integration_reconnect_nat.py.in
index d9714f875..61d2ea966 100755
--- a/src/integration-tests/test_integration_reconnect_nat.py.in
+++ b/src/integration-tests/test_integration_reconnect_nat.py.in
@@ -11,13 +11,14 @@
11# WITHOUT ANY WARRANTY; without even the implied warranty of 11# WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# Affero General Public License for more details. 13# Affero General Public License for more details.
14# 14#
15# You should have received a copy of the GNU Affero General Public License 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/>. 16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17# 17#
18# SPDX-License-Identifier: AGPL3.0-or-later 18# SPDX-License-Identifier: AGPL3.0-or-later
19# 19#
20# 20#
21from __future__ import print_function
21import sys 22import sys
22import os 23import os
23import subprocess 24import subprocess
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/namecache/plugin_namecache_flat.c b/src/namecache/plugin_namecache_flat.c
index 4323780d5..c093cb2a9 100644
--- a/src/namecache/plugin_namecache_flat.c
+++ b/src/namecache/plugin_namecache_flat.c
@@ -173,7 +173,7 @@ database_setup (struct Plugin *plugin)
173 &entry->query)); 173 &entry->query));
174 GNUNET_STRINGS_base64_decode (block, 174 GNUNET_STRINGS_base64_decode (block,
175 strlen (block), 175 strlen (block),
176 &block_buffer); 176 (void**)&block_buffer);
177 entry->block = (struct GNUNET_GNSRECORD_Block *) block_buffer; 177 entry->block = (struct GNUNET_GNSRECORD_Block *) block_buffer;
178 if (GNUNET_OK != 178 if (GNUNET_OK !=
179 GNUNET_CONTAINER_multihashmap_put (plugin->hm, 179 GNUNET_CONTAINER_multihashmap_put (plugin->hm,
diff --git a/src/namecache/test_plugin_namecache.c b/src/namecache/test_plugin_namecache.c
index c2a630a46..20900a3f6 100644
--- a/src/namecache/test_plugin_namecache.c
+++ b/src/namecache/test_plugin_namecache.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -102,7 +102,7 @@ run (void *cls, char *const *args, const char *cfgfile,
102int 102int
103main (int argc, char *argv[]) 103main (int argc, char *argv[])
104{ 104{
105 char cfg_name[128]; 105 char cfg_name[PATH_MAX];
106 char *const xargv[] = { 106 char *const xargv[] = {
107 "test-plugin-namecache", 107 "test-plugin-namecache",
108 "-c", 108 "-c",
diff --git a/src/namestore/gnunet-service-namestore.c b/src/namestore/gnunet-service-namestore.c
index b1f8fcf4c..45be0fe75 100644
--- a/src/namestore/gnunet-service-namestore.c
+++ b/src/namestore/gnunet-service-namestore.c
@@ -124,7 +124,7 @@ struct ZoneIteration
124 * message and free the data structure once @e cache_ops is zero. 124 * message and free the data structure once @e cache_ops is zero.
125 */ 125 */
126 int send_end; 126 int send_end;
127 127
128}; 128};
129 129
130 130
@@ -268,7 +268,7 @@ struct CacheOperation
268 * for if applicable, can be NULL. 268 * for if applicable, can be NULL.
269 */ 269 */
270 struct ZoneIteration *zi; 270 struct ZoneIteration *zi;
271 271
272 /** 272 /**
273 * Client's request ID. 273 * Client's request ID.
274 */ 274 */
@@ -318,12 +318,12 @@ struct StoreActivity
318 318
319/** 319/**
320 * Entry in list of cached nick resolutions. 320 * Entry in list of cached nick resolutions.
321 */ 321 */
322struct NickCache 322struct NickCache
323{ 323{
324 /** 324 /**
325 * Zone the cache entry is for. 325 * Zone the cache entry is for.
326 */ 326 */
327 struct GNUNET_CRYPTO_EcdsaPrivateKey zone; 327 struct GNUNET_CRYPTO_EcdsaPrivateKey zone;
328 328
329 /** 329 /**
@@ -339,7 +339,7 @@ struct NickCache
339 339
340 340
341/** 341/**
342 * We cache nick records to reduce DB load. 342 * We cache nick records to reduce DB load.
343 */ 343 */
344static struct NickCache nick_cache[NC_SIZE]; 344static struct NickCache nick_cache[NC_SIZE];
345 345
@@ -489,7 +489,7 @@ free_store_activity (struct StoreActivity *sa)
489 * record, which (if found) is then copied to @a cls for future use. 489 * record, which (if found) is then copied to @a cls for future use.
490 * 490 *
491 * @param cls a `struct GNUNET_GNSRECORD_Data **` for storing the nick (if found) 491 * @param cls a `struct GNUNET_GNSRECORD_Data **` for storing the nick (if found)
492 * @param seq sequence number of the record 492 * @param seq sequence number of the record, MUST NOT BE ZERO
493 * @param private_key the private key of the zone (unused) 493 * @param private_key the private key of the zone (unused)
494 * @param label should be #GNUNET_GNS_EMPTY_LABEL_AT 494 * @param label should be #GNUNET_GNS_EMPTY_LABEL_AT
495 * @param rd_count number of records in @a rd 495 * @param rd_count number of records in @a rd
@@ -506,7 +506,7 @@ lookup_nick_it (void *cls,
506 struct GNUNET_GNSRECORD_Data **res = cls; 506 struct GNUNET_GNSRECORD_Data **res = cls;
507 507
508 (void) private_key; 508 (void) private_key;
509 (void) seq; 509 GNUNET_assert (0 != seq);
510 if (0 != strcmp (label, GNUNET_GNS_EMPTY_LABEL_AT)) 510 if (0 != strcmp (label, GNUNET_GNS_EMPTY_LABEL_AT))
511 { 511 {
512 GNUNET_break (0); 512 GNUNET_break (0);
@@ -607,7 +607,7 @@ get_nick_record (const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone)
607 return nick; 607 return nick;
608 } 608 }
609 } 609 }
610 610
611 nick = NULL; 611 nick = NULL;
612 res = GSN_database->lookup_records (GSN_database->cls, 612 res = GSN_database->lookup_records (GSN_database->cls,
613 zone, 613 zone,
@@ -872,7 +872,7 @@ zone_iteration_done_client_continue (struct ZoneIteration *zi)
872 em->r_id = htonl (zi->request_id); 872 em->r_id = htonl (zi->request_id);
873 GNUNET_MQ_send (zi->nc->mq, 873 GNUNET_MQ_send (zi->nc->mq,
874 env); 874 env);
875 875
876 GNUNET_CONTAINER_DLL_remove (zi->nc->op_head, 876 GNUNET_CONTAINER_DLL_remove (zi->nc->op_head,
877 zi->nc->op_tail, 877 zi->nc->op_tail,
878 zi); 878 zi);
@@ -1270,9 +1270,16 @@ struct RecordLookupContext
1270 1270
1271 1271
1272/** 1272/**
1273 * FIXME. 1273 * Function called by the namestore plugin when we are trying to lookup
1274 * a record as part of #handle_record_lookup(). Merges all results into
1275 * the context.
1274 * 1276 *
1275 * @param seq sequence number of the record 1277 * @param cls closure with a `struct RecordLookupContext`
1278 * @param seq unique serial number of the record, MUST NOT BE ZERO
1279 * @param zone_key private key of the zone
1280 * @param label name that is being mapped (at most 255 characters long)
1281 * @param rd_count number of entries in @a rd array
1282 * @param rd array of records with data to store
1276 */ 1283 */
1277static void 1284static void
1278lookup_it (void *cls, 1285lookup_it (void *cls,
@@ -1285,7 +1292,7 @@ lookup_it (void *cls,
1285 struct RecordLookupContext *rlc = cls; 1292 struct RecordLookupContext *rlc = cls;
1286 1293
1287 (void) private_key; 1294 (void) private_key;
1288 (void) seq; 1295 GNUNET_assert (0 != seq);
1289 if (0 != strcmp (label, 1296 if (0 != strcmp (label,
1290 rlc->label)) 1297 rlc->label))
1291 return; 1298 return;
@@ -1609,7 +1616,7 @@ handle_record_store (void *cls,
1609 conv_name)) || 1616 conv_name)) ||
1610 (GNUNET_GNSRECORD_TYPE_NICK != rd[i].record_type) ) 1617 (GNUNET_GNSRECORD_TYPE_NICK != rd[i].record_type) )
1611 rd_clean_off++; 1618 rd_clean_off++;
1612 1619
1613 if ( (0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, 1620 if ( (0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT,
1614 conv_name)) && 1621 conv_name)) &&
1615 (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) ) 1622 (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) )
@@ -1680,7 +1687,7 @@ struct ZoneToNameCtx
1680 * Zone to name iterator 1687 * Zone to name iterator
1681 * 1688 *
1682 * @param cls struct ZoneToNameCtx * 1689 * @param cls struct ZoneToNameCtx *
1683 * @param seq sequence number of the record 1690 * @param seq sequence number of the record, MUST NOT BE ZERO
1684 * @param zone_key the zone key 1691 * @param zone_key the zone key
1685 * @param name name 1692 * @param name name
1686 * @param rd_count number of records in @a rd 1693 * @param rd_count number of records in @a rd
@@ -1704,7 +1711,7 @@ handle_zone_to_name_it (void *cls,
1704 char *name_tmp; 1711 char *name_tmp;
1705 char *rd_tmp; 1712 char *rd_tmp;
1706 1713
1707 (void) seq; 1714 GNUNET_assert (0 != seq);
1708 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1709 "Found result for zone-to-name lookup: `%s'\n", 1716 "Found result for zone-to-name lookup: `%s'\n",
1710 name); 1717 name);
@@ -1822,7 +1829,7 @@ struct ZoneIterationProcResult
1822 * Process results for zone iteration from database 1829 * Process results for zone iteration from database
1823 * 1830 *
1824 * @param cls struct ZoneIterationProcResult 1831 * @param cls struct ZoneIterationProcResult
1825 * @param seq sequence number of the record 1832 * @param seq sequence number of the record, MUST NOT BE ZERO
1826 * @param zone_key the zone key 1833 * @param zone_key the zone key
1827 * @param name name 1834 * @param name name
1828 * @param rd_count number of records for this name 1835 * @param rd_count number of records for this name
@@ -1839,6 +1846,7 @@ zone_iterate_proc (void *cls,
1839 struct ZoneIterationProcResult *proc = cls; 1846 struct ZoneIterationProcResult *proc = cls;
1840 int do_refresh_block; 1847 int do_refresh_block;
1841 1848
1849 GNUNET_assert (0 != seq);
1842 if ( (NULL == zone_key) && 1850 if ( (NULL == zone_key) &&
1843 (NULL == name) ) 1851 (NULL == name) )
1844 { 1852 {
@@ -1876,7 +1884,7 @@ zone_iterate_proc (void *cls,
1876 do_refresh_block = GNUNET_YES; 1884 do_refresh_block = GNUNET_YES;
1877 break; 1885 break;
1878 } 1886 }
1879 if (GNUNET_YES == do_refresh_block) 1887 if (GNUNET_YES == do_refresh_block)
1880 refresh_block (NULL, 1888 refresh_block (NULL,
1881 proc->zi, 1889 proc->zi,
1882 0, 1890 0,
@@ -2116,7 +2124,7 @@ monitor_iteration_next (void *cls);
2116 * A #GNUNET_NAMESTORE_RecordIterator for monitors. 2124 * A #GNUNET_NAMESTORE_RecordIterator for monitors.
2117 * 2125 *
2118 * @param cls a 'struct ZoneMonitor *' with information about the monitor 2126 * @param cls a 'struct ZoneMonitor *' with information about the monitor
2119 * @param seq sequence number of the record 2127 * @param seq sequence number of the record, MUST NOT BE ZERO
2120 * @param zone_key zone key of the zone 2128 * @param zone_key zone key of the zone
2121 * @param name name 2129 * @param name name
2122 * @param rd_count number of records in @a rd 2130 * @param rd_count number of records in @a rd
@@ -2132,6 +2140,7 @@ monitor_iterate_cb (void *cls,
2132{ 2140{
2133 struct ZoneMonitor *zm = cls; 2141 struct ZoneMonitor *zm = cls;
2134 2142
2143 GNUNET_assert (0 != seq);
2135 zm->seq = seq; 2144 zm->seq = seq;
2136 GNUNET_assert (NULL != name); 2145 GNUNET_assert (NULL != name);
2137 GNUNET_STATISTICS_update (statistics, 2146 GNUNET_STATISTICS_update (statistics,
diff --git a/src/namestore/plugin_namestore_heap.c b/src/namestore/plugin_namestore_heap.c
index 78e99442c..01cf592ea 100644
--- a/src/namestore/plugin_namestore_heap.c
+++ b/src/namestore/plugin_namestore_heap.c
@@ -79,11 +79,42 @@ struct FlatFileEntry
79 */ 79 */
80 char *label; 80 char *label;
81 81
82
83}; 82};
84 83
85 84
86/** 85/**
86 * Hash contactenation of @a pkey and @a label into @a h
87 *
88 * @param pkey a key
89 * @param label a label
90 * @param h[out] initialized hash
91 */
92static void
93hash_pkey_and_label (const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
94 const char *label,
95 struct GNUNET_HashCode *h)
96{
97 char *key;
98 size_t label_len;
99 size_t key_len;
100
101 label_len = strlen (label);
102 key_len = label_len + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey);
103 key = GNUNET_malloc (key_len);
104 GNUNET_memcpy (key,
105 label,
106 label_len);
107 GNUNET_memcpy (key + label_len,
108 pkey,
109 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
110 GNUNET_CRYPTO_hash (key,
111 key_len,
112 h);
113 GNUNET_free (key);
114}
115
116
117/**
87 * Initialize the database connections and associated 118 * Initialize the database connections and associated
88 * data structures (create tables and indices 119 * data structures (create tables and indices
89 * as needed as well). 120 * as needed as well).
@@ -262,23 +293,9 @@ database_setup (struct Plugin *plugin)
262 GNUNET_free (private_key); 293 GNUNET_free (private_key);
263 } 294 }
264 295
265 { 296 hash_pkey_and_label (&entry->private_key,
266 char *key; 297 label,
267 size_t key_len; 298 &hkey);
268
269 key_len = strlen (label) + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey);
270 key = GNUNET_malloc (strlen (label) + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
271 GNUNET_memcpy (key,
272 label,
273 strlen (label));
274 GNUNET_memcpy (key+strlen(label),
275 &entry->private_key,
276 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
277 GNUNET_CRYPTO_hash (key,
278 key_len,
279 &hkey);
280 GNUNET_free (key);
281 }
282 if (GNUNET_OK != 299 if (GNUNET_OK !=
283 GNUNET_CONTAINER_multihashmap_put (plugin->hm, 300 GNUNET_CONTAINER_multihashmap_put (plugin->hm,
284 &hkey, 301 &hkey,
@@ -425,24 +442,14 @@ namestore_heap_store_records (void *cls,
425{ 442{
426 struct Plugin *plugin = cls; 443 struct Plugin *plugin = cls;
427 uint64_t rvalue; 444 uint64_t rvalue;
428 size_t key_len;
429 char *key;
430 struct GNUNET_HashCode hkey; 445 struct GNUNET_HashCode hkey;
431 struct FlatFileEntry *entry; 446 struct FlatFileEntry *entry;
432 447
433 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, 448 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
434 UINT64_MAX); 449 UINT64_MAX);
435 key_len = strlen (label) + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey); 450 hash_pkey_and_label (zone_key,
436 key = GNUNET_malloc (key_len); 451 label,
437 GNUNET_memcpy (key, 452 &hkey);
438 label,
439 strlen (label));
440 GNUNET_memcpy (key + strlen(label),
441 zone_key,
442 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
443 GNUNET_CRYPTO_hash (key,
444 key_len,
445 &hkey);
446 GNUNET_CONTAINER_multihashmap_remove_all (plugin->hm, 453 GNUNET_CONTAINER_multihashmap_remove_all (plugin->hm,
447 &hkey); 454 &hkey);
448 if (0 == rd_count) 455 if (0 == rd_count)
@@ -501,27 +508,15 @@ namestore_heap_lookup_records (void *cls,
501 struct Plugin *plugin = cls; 508 struct Plugin *plugin = cls;
502 struct FlatFileEntry *entry; 509 struct FlatFileEntry *entry;
503 struct GNUNET_HashCode hkey; 510 struct GNUNET_HashCode hkey;
504 char *key;
505 size_t key_len;
506 511
507 if (NULL == zone) 512 if (NULL == zone)
508 { 513 {
509 GNUNET_break (0); 514 GNUNET_break (0);
510 return GNUNET_SYSERR; 515 return GNUNET_SYSERR;
511 } 516 }
512 key_len = strlen (label) + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey); 517 hash_pkey_and_label (zone,
513 key = GNUNET_malloc (key_len); 518 label,
514 GNUNET_memcpy (key, 519 &hkey);
515 label,
516 strlen (label));
517 GNUNET_memcpy (key+strlen(label),
518 zone,
519 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
520 GNUNET_CRYPTO_hash (key,
521 key_len,
522 &hkey);
523 GNUNET_free (key);
524
525 entry = GNUNET_CONTAINER_multihashmap_get (plugin->hm, 520 entry = GNUNET_CONTAINER_multihashmap_get (plugin->hm,
526 &hkey); 521 &hkey);
527 522
@@ -529,7 +524,7 @@ namestore_heap_lookup_records (void *cls,
529 return GNUNET_NO; 524 return GNUNET_NO;
530 if (NULL != iter) 525 if (NULL != iter)
531 iter (iter_cls, 526 iter (iter_cls,
532 0, 527 1, /* zero is illegal */
533 &entry->private_key, 528 &entry->private_key,
534 entry->label, 529 entry->label,
535 entry->record_count, 530 entry->record_count,
@@ -609,7 +604,7 @@ iterate_zones (void *cls,
609 } 604 }
610 ic->iter (ic->iter_cls, 605 ic->iter (ic->iter_cls,
611 ic->pos, 606 ic->pos,
612 (NULL == ic->zone) 607 (NULL == ic->zone)
613 ? &entry->private_key 608 ? &entry->private_key
614 : ic->zone, 609 : ic->zone,
615 entry->label, 610 entry->label,
@@ -695,7 +690,7 @@ zone_to_name (void *cls,
695 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) 690 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
696 { 691 {
697 ztn->iter (ztn->iter_cls, 692 ztn->iter (ztn->iter_cls,
698 0, 693 i + 1, /* zero is illegal! */
699 &entry->private_key, 694 &entry->private_key,
700 entry->label, 695 entry->label,
701 entry->record_count, 696 entry->record_count,
diff --git a/src/namestore/plugin_namestore_postgres.c b/src/namestore/plugin_namestore_postgres.c
index 57a8ae2be..f2e065882 100644
--- a/src/namestore/plugin_namestore_postgres.c
+++ b/src/namestore/plugin_namestore_postgres.c
@@ -400,6 +400,7 @@ parse_result_call_iterator (void *cls,
400 { 400 {
401 struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL(record_count)]; 401 struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL(record_count)];
402 402
403 GNUNET_assert (0 != serial);
403 if (GNUNET_OK != 404 if (GNUNET_OK !=
404 GNUNET_GNSRECORD_records_deserialize (data_size, 405 GNUNET_GNSRECORD_records_deserialize (data_size,
405 data, 406 data,
diff --git a/src/namestore/plugin_namestore_sqlite.c b/src/namestore/plugin_namestore_sqlite.c
index 96b0d6457..e4bfcde16 100644
--- a/src/namestore/plugin_namestore_sqlite.c
+++ b/src/namestore/plugin_namestore_sqlite.c
@@ -521,6 +521,7 @@ get_records_and_call_iterator (struct Plugin *plugin,
521 { 521 {
522 struct GNUNET_GNSRECORD_Data rd[record_count]; 522 struct GNUNET_GNSRECORD_Data rd[record_count];
523 523
524 GNUNET_assert (0 != seq);
524 if (GNUNET_OK != 525 if (GNUNET_OK !=
525 GNUNET_GNSRECORD_records_deserialize (data_size, 526 GNUNET_GNSRECORD_records_deserialize (data_size,
526 data, 527 data,
diff --git a/src/namestore/test_plugin_namestore.c b/src/namestore/test_plugin_namestore.c
index b9c7fbef9..9c978749f 100644
--- a/src/namestore/test_plugin_namestore.c
+++ b/src/namestore/test_plugin_namestore.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -107,7 +107,8 @@ test_record (void *cls,
107 GNUNET_snprintf (tname, 107 GNUNET_snprintf (tname,
108 sizeof (tname), 108 sizeof (tname),
109 "a%u", 109 "a%u",
110 (unsigned int ) id); 110 (unsigned int) id);
111 GNUNET_assert (trd_count == rd_count);
111 for (unsigned int i=0;i<trd_count;i++) 112 for (unsigned int i=0;i<trd_count;i++)
112 { 113 {
113 GNUNET_assert (rd[i].data_size == id % 10); 114 GNUNET_assert (rd[i].data_size == id % 10);
@@ -198,7 +199,7 @@ int
198main (int argc, 199main (int argc,
199 char *argv[]) 200 char *argv[])
200{ 201{
201 char cfg_name[128]; 202 char cfg_name[PATH_MAX];
202 char *const xargv[] = { 203 char *const xargv[] = {
203 "test-plugin-namestore", 204 "test-plugin-namestore",
204 "-c", 205 "-c",
diff --git a/src/peerinfo/peerinfo_api.c b/src/peerinfo/peerinfo_api.c
index f2af27c0b..4b56b34c7 100644
--- a/src/peerinfo/peerinfo_api.c
+++ b/src/peerinfo/peerinfo_api.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -565,10 +565,7 @@ GNUNET_PEERINFO_add_peer (struct GNUNET_PEERINFO_Handle *h,
565 struct GNUNET_PeerIdentity peer; 565 struct GNUNET_PeerIdentity peer;
566 566
567 if (NULL == h->mq) 567 if (NULL == h->mq)
568 {
569 GNUNET_break (0);
570 return NULL; 568 return NULL;
571 }
572 GNUNET_assert (GNUNET_OK == 569 GNUNET_assert (GNUNET_OK ==
573 GNUNET_HELLO_get_id (hello, 570 GNUNET_HELLO_get_id (hello,
574 &peer)); 571 &peer));
diff --git a/src/peerstore/Makefile.am b/src/peerstore/Makefile.am
index 3aef05769..c6acdce56 100644
--- a/src/peerstore/Makefile.am
+++ b/src/peerstore/Makefile.am
@@ -107,7 +107,9 @@ check_PROGRAMS = \
107 $(FLAT_TESTS) 107 $(FLAT_TESTS)
108 108
109EXTRA_DIST = \ 109EXTRA_DIST = \
110 test_peerstore_api_data.conf 110 test_peerstore_api_data.conf \
111 test_plugin_peerstore_flat.conf \
112 test_plugin_peerstore_sqlite.conf
111 113
112if ENABLE_TEST_RUN 114if ENABLE_TEST_RUN
113AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; 115AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
diff --git a/src/peerstore/peerstore_api.c b/src/peerstore/peerstore_api.c
index 6abdef43a..243e26c8b 100644
--- a/src/peerstore/peerstore_api.c
+++ b/src/peerstore/peerstore_api.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -76,6 +76,16 @@ struct GNUNET_PEERSTORE_Handle
76 struct GNUNET_CONTAINER_MultiHashMap *watches; 76 struct GNUNET_CONTAINER_MultiHashMap *watches;
77 77
78 /** 78 /**
79 * ID of the task trying to reconnect to the service.
80 */
81 struct GNUNET_SCHEDULER_Task *reconnect_task;
82
83 /**
84 * Delay until we try to reconnect.
85 */
86 struct GNUNET_TIME_Relative reconnect_delay;
87
88 /**
79 * Are we in the process of disconnecting but need to sync first? 89 * Are we in the process of disconnecting but need to sync first?
80 */ 90 */
81 int disconnecting; 91 int disconnecting;
@@ -245,10 +255,72 @@ struct GNUNET_PEERSTORE_WatchContext
245/** 255/**
246 * Close the existing connection to PEERSTORE and reconnect. 256 * Close the existing connection to PEERSTORE and reconnect.
247 * 257 *
248 * @param h handle to the service 258 * @param cls a `struct GNUNET_PEERSTORE_Handle *h`
259 */
260static void
261reconnect (void *cls);
262
263
264/**
265 * Disconnect from the peerstore service.
266 *
267 * @param h peerstore handle to disconnect
268 */
269static void
270disconnect (struct GNUNET_PEERSTORE_Handle *h)
271{
272 struct GNUNET_PEERSTORE_IterateContext *next;
273
274 for (struct GNUNET_PEERSTORE_IterateContext *ic = h->iterate_head;
275 NULL != ic;
276 ic = next)
277 {
278 next = ic->next;
279 if (GNUNET_YES == ic->iterating)
280 {
281 GNUNET_PEERSTORE_Processor icb;
282 void *icb_cls;
283
284 icb = ic->callback;
285 icb_cls = ic->callback_cls;
286 GNUNET_PEERSTORE_iterate_cancel (ic);
287 if (NULL != icb)
288 icb (icb_cls,
289 NULL,
290 "Iteration canceled due to reconnection");
291 }
292 }
293
294 if (NULL != h->mq)
295 {
296 GNUNET_MQ_destroy (h->mq);
297 h->mq = NULL;
298 }
299}
300
301
302/**
303 * Function that will schedule the job that will try
304 * to connect us again to the client.
305 *
306 * @param h peerstore to reconnect
249 */ 307 */
250static void 308static void
251reconnect (struct GNUNET_PEERSTORE_Handle *h); 309disconnect_and_schedule_reconnect (struct GNUNET_PEERSTORE_Handle *h)
310{
311 GNUNET_assert (NULL == h->reconnect_task);
312 disconnect (h);
313 LOG (GNUNET_ERROR_TYPE_DEBUG,
314 "Scheduling task to reconnect to PEERSTORE service in %s.\n",
315 GNUNET_STRINGS_relative_time_to_string (h->reconnect_delay,
316 GNUNET_YES));
317 h->reconnect_task =
318 GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
319 &reconnect,
320 h);
321 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
322}
323
252 324
253 325
254/** 326/**
@@ -288,7 +360,7 @@ handle_client_error (void *cls,
288 LOG (GNUNET_ERROR_TYPE_ERROR, 360 LOG (GNUNET_ERROR_TYPE_ERROR,
289 "Received an error notification from MQ of type: %d\n", 361 "Received an error notification from MQ of type: %d\n",
290 error); 362 error);
291 reconnect (h); 363 disconnect_and_schedule_reconnect (h);
292} 364}
293 365
294 366
@@ -345,7 +417,7 @@ destroy_watch (void *cls,
345 * @param h Handle to the service. 417 * @param h Handle to the service.
346 */ 418 */
347static void 419static void
348do_disconnect (struct GNUNET_PEERSTORE_Handle *h) 420final_disconnect (struct GNUNET_PEERSTORE_Handle *h)
349{ 421{
350 if (NULL != h->mq) 422 if (NULL != h->mq)
351 { 423 {
@@ -419,7 +491,7 @@ GNUNET_PEERSTORE_disconnect (struct GNUNET_PEERSTORE_Handle *h,
419 while (NULL != (sc = h->store_head)) 491 while (NULL != (sc = h->store_head))
420 GNUNET_PEERSTORE_store_cancel (sc); 492 GNUNET_PEERSTORE_store_cancel (sc);
421 } 493 }
422 do_disconnect (h); 494 final_disconnect (h);
423} 495}
424 496
425 497
@@ -443,8 +515,9 @@ GNUNET_PEERSTORE_store_cancel (struct GNUNET_PEERSTORE_StoreContext *sc)
443 GNUNET_free (sc->value); 515 GNUNET_free (sc->value);
444 GNUNET_free (sc->key); 516 GNUNET_free (sc->key);
445 GNUNET_free (sc); 517 GNUNET_free (sc);
446 if ((GNUNET_YES == h->disconnecting) && (NULL == h->store_head)) 518 if ( (GNUNET_YES == h->disconnecting) &&
447 do_disconnect (h); 519 (NULL == h->store_head) )
520 final_disconnect (h);
448} 521}
449 522
450 523
@@ -530,7 +603,7 @@ handle_iterate_end (void *cls,
530 { 603 {
531 LOG (GNUNET_ERROR_TYPE_ERROR, 604 LOG (GNUNET_ERROR_TYPE_ERROR,
532 _("Unexpected iteration response, this should not happen.\n")); 605 _("Unexpected iteration response, this should not happen.\n"));
533 reconnect (h); 606 disconnect_and_schedule_reconnect (h);
534 return; 607 return;
535 } 608 }
536 callback = ic->callback; 609 callback = ic->callback;
@@ -538,7 +611,10 @@ handle_iterate_end (void *cls,
538 ic->iterating = GNUNET_NO; 611 ic->iterating = GNUNET_NO;
539 GNUNET_PEERSTORE_iterate_cancel (ic); 612 GNUNET_PEERSTORE_iterate_cancel (ic);
540 if (NULL != callback) 613 if (NULL != callback)
541 callback (callback_cls, NULL, NULL); 614 callback (callback_cls,
615 NULL,
616 NULL);
617 h->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
542} 618}
543 619
544 620
@@ -579,7 +655,7 @@ handle_iterate_result (void *cls,
579 { 655 {
580 LOG (GNUNET_ERROR_TYPE_ERROR, 656 LOG (GNUNET_ERROR_TYPE_ERROR,
581 _("Unexpected iteration response, this should not happen.\n")); 657 _("Unexpected iteration response, this should not happen.\n"));
582 reconnect (h); 658 disconnect_and_schedule_reconnect (h);
583 return; 659 return;
584 } 660 }
585 ic->iterating = GNUNET_YES; 661 ic->iterating = GNUNET_YES;
@@ -715,7 +791,7 @@ handle_watch_record (void *cls,
715 record = PEERSTORE_parse_record_message (msg); 791 record = PEERSTORE_parse_record_message (msg);
716 if (NULL == record) 792 if (NULL == record)
717 { 793 {
718 reconnect (h); 794 disconnect_and_schedule_reconnect (h);
719 return; 795 return;
720 } 796 }
721 PEERSTORE_hash_key (record->sub_system, 797 PEERSTORE_hash_key (record->sub_system,
@@ -730,13 +806,14 @@ handle_watch_record (void *cls,
730 LOG (GNUNET_ERROR_TYPE_ERROR, 806 LOG (GNUNET_ERROR_TYPE_ERROR,
731 _("Received a watch result for a non existing watch.\n")); 807 _("Received a watch result for a non existing watch.\n"));
732 PEERSTORE_destroy_record (record); 808 PEERSTORE_destroy_record (record);
733 reconnect (h); 809 disconnect_and_schedule_reconnect (h);
734 return; 810 return;
735 } 811 }
736 if (NULL != wc->callback) 812 if (NULL != wc->callback)
737 wc->callback (wc->callback_cls, 813 wc->callback (wc->callback_cls,
738 record, 814 record,
739 NULL); 815 NULL);
816 h->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
740 PEERSTORE_destroy_record (record); 817 PEERSTORE_destroy_record (record);
741} 818}
742 819
@@ -744,11 +821,12 @@ handle_watch_record (void *cls,
744/** 821/**
745 * Close the existing connection to PEERSTORE and reconnect. 822 * Close the existing connection to PEERSTORE and reconnect.
746 * 823 *
747 * @param h handle to the service 824 * @param cls a `struct GNUNET_PEERSTORE_Handle *`
748 */ 825 */
749static void 826static void
750reconnect (struct GNUNET_PEERSTORE_Handle *h) 827reconnect (void *cls)
751{ 828{
829 struct GNUNET_PEERSTORE_Handle *h = cls;
752 struct GNUNET_MQ_MessageHandler mq_handlers[] = { 830 struct GNUNET_MQ_MessageHandler mq_handlers[] = {
753 GNUNET_MQ_hd_fixed_size (iterate_end, 831 GNUNET_MQ_hd_fixed_size (iterate_end,
754 GNUNET_MESSAGE_TYPE_PEERSTORE_ITERATE_END, 832 GNUNET_MESSAGE_TYPE_PEERSTORE_ITERATE_END,
@@ -764,34 +842,10 @@ reconnect (struct GNUNET_PEERSTORE_Handle *h)
764 h), 842 h),
765 GNUNET_MQ_handler_end () 843 GNUNET_MQ_handler_end ()
766 }; 844 };
767 struct GNUNET_PEERSTORE_IterateContext *ic;
768 struct GNUNET_PEERSTORE_IterateContext *next;
769 GNUNET_PEERSTORE_Processor icb;
770 void *icb_cls;
771 struct GNUNET_PEERSTORE_StoreContext *sc;
772 struct GNUNET_MQ_Envelope *ev; 845 struct GNUNET_MQ_Envelope *ev;
773 846
774 LOG (GNUNET_ERROR_TYPE_DEBUG, 847 LOG (GNUNET_ERROR_TYPE_DEBUG,
775 "Reconnecting...\n"); 848 "Reconnecting...\n");
776 for (ic = h->iterate_head; NULL != ic; ic = next)
777 {
778 next = ic->next;
779 if (GNUNET_YES == ic->iterating)
780 {
781 icb = ic->callback;
782 icb_cls = ic->callback_cls;
783 GNUNET_PEERSTORE_iterate_cancel (ic);
784 if (NULL != icb)
785 icb (icb_cls,
786 NULL,
787 "Iteration canceled due to reconnection");
788 }
789 }
790 if (NULL != h->mq)
791 {
792 GNUNET_MQ_destroy (h->mq);
793 h->mq = NULL;
794 }
795 h->mq = GNUNET_CLIENT_connect (h->cfg, 849 h->mq = GNUNET_CLIENT_connect (h->cfg,
796 "peerstore", 850 "peerstore",
797 mq_handlers, 851 mq_handlers,
@@ -805,7 +859,9 @@ reconnect (struct GNUNET_PEERSTORE_Handle *h)
805 GNUNET_CONTAINER_multihashmap_iterate (h->watches, 859 GNUNET_CONTAINER_multihashmap_iterate (h->watches,
806 &rewatch_it, 860 &rewatch_it,
807 h); 861 h);
808 for (ic = h->iterate_head; NULL != ic; ic = ic->next) 862 for (struct GNUNET_PEERSTORE_IterateContext *ic = h->iterate_head;
863 NULL != ic;
864 ic = ic->next)
809 { 865 {
810 ev = PEERSTORE_create_record_mq_envelope (ic->sub_system, 866 ev = PEERSTORE_create_record_mq_envelope (ic->sub_system,
811 &ic->peer, 867 &ic->peer,
@@ -816,7 +872,9 @@ reconnect (struct GNUNET_PEERSTORE_Handle *h)
816 GNUNET_MESSAGE_TYPE_PEERSTORE_ITERATE); 872 GNUNET_MESSAGE_TYPE_PEERSTORE_ITERATE);
817 GNUNET_MQ_send (h->mq, ev); 873 GNUNET_MQ_send (h->mq, ev);
818 } 874 }
819 for (sc = h->store_head; NULL != sc; sc = sc->next) 875 for (struct GNUNET_PEERSTORE_StoreContext *sc = h->store_head;
876 NULL != sc;
877 sc = sc->next)
820 { 878 {
821 ev = PEERSTORE_create_record_mq_envelope (sc->sub_system, 879 ev = PEERSTORE_create_record_mq_envelope (sc->sub_system,
822 &sc->peer, 880 &sc->peer,
diff --git a/src/peerstore/plugin_peerstore_flat.c b/src/peerstore/plugin_peerstore_flat.c
index cd1837e1a..0cd2522ec 100644
--- a/src/peerstore/plugin_peerstore_flat.c
+++ b/src/peerstore/plugin_peerstore_flat.c
@@ -440,7 +440,7 @@ database_setup (struct Plugin *plugin)
440 o = NULL; 440 o = NULL;
441 s = GNUNET_STRINGS_base64_decode (peer, 441 s = GNUNET_STRINGS_base64_decode (peer,
442 strlen (peer), 442 strlen (peer),
443 &o); 443 (void**)&o);
444 if (sizeof (struct GNUNET_PeerIdentity) == s) 444 if (sizeof (struct GNUNET_PeerIdentity) == s)
445 GNUNET_memcpy (&entry->peer, 445 GNUNET_memcpy (&entry->peer,
446 o, 446 o,
@@ -451,7 +451,7 @@ database_setup (struct Plugin *plugin)
451 } 451 }
452 entry->value_size = GNUNET_STRINGS_base64_decode (value, 452 entry->value_size = GNUNET_STRINGS_base64_decode (value,
453 strlen (value), 453 strlen (value),
454 (char**)&entry->value); 454 (void**)&entry->value);
455 if (GNUNET_SYSERR == 455 if (GNUNET_SYSERR ==
456 GNUNET_STRINGS_fancy_time_to_absolute (expiry, 456 GNUNET_STRINGS_fancy_time_to_absolute (expiry,
457 &entry->expiry)) 457 &entry->expiry))
diff --git a/src/peerstore/test_plugin_peerstore.c b/src/peerstore/test_plugin_peerstore.c
index 5f18d1532..d6be5f06d 100644
--- a/src/peerstore/test_plugin_peerstore.c
+++ b/src/peerstore/test_plugin_peerstore.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -188,7 +188,7 @@ run (void *cls,
188int 188int
189main (int argc, char *argv[]) 189main (int argc, char *argv[])
190{ 190{
191 char cfg_name[128]; 191 char cfg_name[PATH_MAX];
192 char *const xargv[] = { 192 char *const xargv[] = {
193 "test-plugin-peerstore", 193 "test-plugin-peerstore",
194 "-c", 194 "-c",
diff --git a/src/pq/pq_result_helper.c b/src/pq/pq_result_helper.c
index b0f0a8a6b..336ca8c42 100644
--- a/src/pq/pq_result_helper.c
+++ b/src/pq/pq_result_helper.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
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/rest-plugins/Makefile.am b/src/rest-plugins/Makefile.am
index f36154ebd..a49ab0ef0 100644
--- a/src/rest-plugins/Makefile.am
+++ b/src/rest-plugins/Makefile.am
@@ -67,6 +67,7 @@ libgnunet_plugin_rest_copying_la_LDFLAGS = \
67libgnunet_plugin_rest_peerinfo_la_SOURCES = \ 67libgnunet_plugin_rest_peerinfo_la_SOURCES = \
68 plugin_rest_peerinfo.c 68 plugin_rest_peerinfo.c
69libgnunet_plugin_rest_peerinfo_la_LIBADD = \ 69libgnunet_plugin_rest_peerinfo_la_LIBADD = \
70 $(top_builddir)/src/hello/libgnunethello.la \
70 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ 71 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
71 $(top_builddir)/src/rest/libgnunetrest.la \ 72 $(top_builddir)/src/rest/libgnunetrest.la \
72 $(top_builddir)/src/json/libgnunetjson.la \ 73 $(top_builddir)/src/json/libgnunetjson.la \
@@ -104,6 +105,7 @@ libgnunet_plugin_rest_namestore_la_LDFLAGS = \
104libgnunet_plugin_rest_gns_la_SOURCES = \ 105libgnunet_plugin_rest_gns_la_SOURCES = \
105 plugin_rest_gns.c 106 plugin_rest_gns.c
106libgnunet_plugin_rest_gns_la_LIBADD = \ 107libgnunet_plugin_rest_gns_la_LIBADD = \
108 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
107 $(top_builddir)/src/gns/libgnunetgns.la \ 109 $(top_builddir)/src/gns/libgnunetgns.la \
108 $(top_builddir)/src/rest/libgnunetrest.la \ 110 $(top_builddir)/src/rest/libgnunetrest.la \
109 $(top_builddir)/src/identity/libgnunetidentity.la \ 111 $(top_builddir)/src/identity/libgnunetidentity.la \
diff --git a/src/rest-plugins/plugin_rest_openid_connect.c b/src/rest-plugins/plugin_rest_openid_connect.c
index 5fa17076d..e755f079b 100644
--- a/src/rest-plugins/plugin_rest_openid_connect.c
+++ b/src/rest-plugins/plugin_rest_openid_connect.c
@@ -935,12 +935,24 @@ oidc_ticket_issue_cb (void* cls,
935 &handle->ticket, 935 &handle->ticket,
936 handle->oidc->nonce); 936 handle->oidc->nonce);
937 code_base64_final_string = base64_encode (code_json_string); 937 code_base64_final_string = base64_encode (code_json_string);
938 GNUNET_asprintf (&redirect_uri, "%s.%s/%s?%s=%s&state=%s", 938 if ( (NULL != handle->redirect_prefix) &&
939 handle->redirect_prefix, 939 (NULL != handle->redirect_suffix) &&
940 handle->tld, 940 (NULL != handle->tld) )
941 handle->redirect_suffix, 941 {
942 handle->oidc->response_type, 942
943 code_base64_final_string, handle->oidc->state); 943 GNUNET_asprintf (&redirect_uri, "%s.%s/%s?%s=%s&state=%s",
944 handle->redirect_prefix,
945 handle->tld,
946 handle->redirect_suffix,
947 handle->oidc->response_type,
948 code_base64_final_string, handle->oidc->state);
949 } else {
950 GNUNET_asprintf (&redirect_uri, "%s?%s=%s&state=%s",
951 handle->oidc->redirect_uri,
952 handle->oidc->response_type,
953 code_base64_final_string, handle->oidc->state);
954
955 }
944 resp = GNUNET_REST_create_response (""); 956 resp = GNUNET_REST_create_response ("");
945 MHD_add_response_header (resp, "Location", redirect_uri); 957 MHD_add_response_header (resp, "Location", redirect_uri);
946 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); 958 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
@@ -1095,13 +1107,25 @@ build_redirect (void *cls)
1095 1107
1096 if (GNUNET_YES == handle->oidc->user_cancelled) 1108 if (GNUNET_YES == handle->oidc->user_cancelled)
1097 { 1109 {
1098 GNUNET_asprintf (&redirect_uri, "%s.%s/%s?error=%s&error_description=%s&state=%s", 1110 if ( (NULL != handle->redirect_prefix) &&
1099 handle->redirect_prefix, 1111 (NULL != handle->redirect_suffix) &&
1100 handle->tld, 1112 (NULL != handle->tld) )
1101 handle->redirect_suffix, 1113 {
1102 "access_denied", 1114 GNUNET_asprintf (&redirect_uri, "%s.%s/%s?error=%s&error_description=%s&state=%s",
1103 "User denied access", 1115 handle->redirect_prefix,
1104 handle->oidc->state); 1116 handle->tld,
1117 handle->redirect_suffix,
1118 "access_denied",
1119 "User denied access",
1120 handle->oidc->state);
1121 } else {
1122 GNUNET_asprintf (&redirect_uri, "%s?error=%s&error_description=%s&state=%s",
1123 handle->oidc->redirect_uri,
1124 "access_denied",
1125 "User denied access",
1126 handle->oidc->state);
1127
1128 }
1105 resp = GNUNET_REST_create_response (""); 1129 resp = GNUNET_REST_create_response ("");
1106 MHD_add_response_header (resp, "Location", redirect_uri); 1130 MHD_add_response_header (resp, "Location", redirect_uri);
1107 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); 1131 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
@@ -1137,25 +1161,35 @@ lookup_redirect_uri_result (void *cls,
1137 if (GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT != rd[i].record_type) 1161 if (GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT != rd[i].record_type)
1138 continue; 1162 continue;
1139 if (0 != strncmp (rd[i].data, 1163 if (0 != strncmp (rd[i].data,
1140 handle->oidc->redirect_uri, 1164 handle->oidc->redirect_uri,
1141 rd[i].data_size)) 1165 rd[i].data_size))
1142 continue; 1166 continue;
1143 tmp = GNUNET_strndup (rd[i].data, 1167 tmp = GNUNET_strndup (rd[i].data,
1144 rd[i].data_size); 1168 rd[i].data_size);
1145 pos = strrchr (tmp, 1169 if (NULL == strstr (tmp,
1146 (unsigned char) '.'); 1170 handle->oidc->client_id))
1147 *pos = '\0'; 1171 {
1148 handle->redirect_prefix = GNUNET_strdup (tmp); 1172 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1149 tmp_key_str = pos + 1; 1173 "Redirect uri %s does not contain client_id %s",
1150 pos = strchr (tmp_key_str, 1174 tmp,
1151 (unsigned char) '/'); 1175 handle->oidc->client_id);
1152 *pos = '\0'; 1176 } else {
1153 handle->redirect_suffix = GNUNET_strdup (pos + 1); 1177
1154 1178 pos = strrchr (tmp,
1155 GNUNET_STRINGS_string_to_data (tmp_key_str, 1179 (unsigned char) '.');
1156 strlen (tmp_key_str), 1180 *pos = '\0';
1157 &redirect_zone, 1181 handle->redirect_prefix = GNUNET_strdup (tmp);
1158 sizeof (redirect_zone)); 1182 tmp_key_str = pos + 1;
1183 pos = strchr (tmp_key_str,
1184 (unsigned char) '/');
1185 *pos = '\0';
1186 handle->redirect_suffix = GNUNET_strdup (pos + 1);
1187
1188 GNUNET_STRINGS_string_to_data (tmp_key_str,
1189 strlen (tmp_key_str),
1190 &redirect_zone,
1191 sizeof (redirect_zone));
1192 }
1159 GNUNET_SCHEDULER_add_now (&build_redirect, handle); 1193 GNUNET_SCHEDULER_add_now (&build_redirect, handle);
1160 GNUNET_free (tmp); 1194 GNUNET_free (tmp);
1161 return; 1195 return;
@@ -1300,7 +1334,7 @@ build_authz_response (void *cls)
1300 { 1334 {
1301 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_SCOPE); 1335 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_SCOPE);
1302 handle->edesc=GNUNET_strdup ("The requested scope is invalid, unknown, or " 1336 handle->edesc=GNUNET_strdup ("The requested scope is invalid, unknown, or "
1303 "malformed."); 1337 "malformed.");
1304 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); 1338 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1305 GNUNET_free (expected_scope); 1339 GNUNET_free (expected_scope);
1306 return; 1340 return;
@@ -1337,7 +1371,7 @@ tld_iter (void *cls,
1337 return; 1371 return;
1338 } 1372 }
1339 if (0 == memcmp (&pkey, &handle->oidc->client_pkey, 1373 if (0 == memcmp (&pkey, &handle->oidc->client_pkey,
1340 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) 1374 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1341 handle->tld = GNUNET_strdup (option+1); 1375 handle->tld = GNUNET_strdup (option+1);
1342} 1376}
1343 1377
@@ -1431,7 +1465,7 @@ authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
1431 tld_iter, 1465 tld_iter,
1432 handle); 1466 handle);
1433 if (NULL == handle->tld) 1467 if (NULL == handle->tld)
1434 handle->tld = GNUNET_strdup (tmp_ego->keystring); 1468 handle->tld = GNUNET_strdup (handle->oidc->client_id);
1435 GNUNET_SCHEDULER_add_now (&build_authz_response, handle); 1469 GNUNET_SCHEDULER_add_now (&build_authz_response, handle);
1436} 1470}
1437 1471
diff --git a/src/revocation/test_local_revocation.py.in b/src/revocation/test_local_revocation.py.in
index 212e8e777..5caa616ca 100644
--- a/src/revocation/test_local_revocation.py.in
+++ b/src/revocation/test_local_revocation.py.in
@@ -19,6 +19,7 @@
19# 19#
20# Testcase for ego revocation 20# Testcase for ego revocation
21from __future__ import print_function 21from __future__ import print_function
22from builtins import str
22import sys 23import sys
23import os 24import os
24import subprocess 25import subprocess
diff --git a/src/rps/gnunet-rps-profiler.c b/src/rps/gnunet-rps-profiler.c
index 36a167203..98fc8dccb 100644
--- a/src/rps/gnunet-rps-profiler.c
+++ b/src/rps/gnunet-rps-profiler.c
@@ -1574,7 +1574,7 @@ static void mal_init_peer (struct RPSPeer *rps_peer)
1574static void 1574static void
1575mal_pre (struct RPSPeer *rps_peer, struct GNUNET_RPS_Handle *h) 1575mal_pre (struct RPSPeer *rps_peer, struct GNUNET_RPS_Handle *h)
1576{ 1576{
1577 #ifdef ENABLE_MALICIOUS 1577 #if ENABLE_MALICIOUS
1578 uint32_t num_mal_peers; 1578 uint32_t num_mal_peers;
1579 1579
1580 GNUNET_assert ( (1 >= portion) && 1580 GNUNET_assert ( (1 >= portion) &&
@@ -1605,7 +1605,7 @@ mal_cb (struct RPSPeer *rps_peer)
1605 return; 1605 return;
1606 } 1606 }
1607 1607
1608 #ifdef ENABLE_MALICIOUS 1608 #if ENABLE_MALICIOUS
1609 GNUNET_assert ( (1 >= portion) && 1609 GNUNET_assert ( (1 >= portion) &&
1610 (0 < portion) ); 1610 (0 < portion) );
1611 num_mal_peers = round (portion * num_peers); 1611 num_mal_peers = round (portion * num_peers);
@@ -2636,9 +2636,11 @@ stat_iterator (void *cls,
2636 (void) subsystem; 2636 (void) subsystem;
2637 (void) is_persistent; 2637 (void) is_persistent;
2638 2638
2639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got stat value: %s - %" PRIu64 "\n", 2639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2640 name, 2640 "Got stat value: %s - %" PRIu64 " (%u)\n",
2641 value); 2641 name,
2642 value,
2643 rps_peer->index);
2642 to_file (rps_peer->file_name_stats, 2644 to_file (rps_peer->file_name_stats,
2643 "%s: %" PRIu64 "\n", 2645 "%s: %" PRIu64 "\n",
2644 name, 2646 name,
@@ -2650,7 +2652,9 @@ stat_iterator (void *cls,
2650 return GNUNET_OK; 2652 return GNUNET_OK;
2651} 2653}
2652 2654
2653void post_profiler (struct RPSPeer *rps_peer) 2655
2656void
2657post_profiler (struct RPSPeer *rps_peer)
2654{ 2658{
2655 if (COLLECT_STATISTICS != cur_test_run.have_collect_statistics) 2659 if (COLLECT_STATISTICS != cur_test_run.have_collect_statistics)
2656 { 2660 {
diff --git a/src/rps/gnunet-service-rps.c b/src/rps/gnunet-service-rps.c
index 08f2450f5..05d5c91c3 100644
--- a/src/rps/gnunet-service-rps.c
+++ b/src/rps/gnunet-service-rps.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -261,7 +261,7 @@ struct ChannelCtx
261}; 261};
262 262
263 263
264#ifdef ENABLE_MALICIOUS 264#if ENABLE_MALICIOUS
265 265
266/** 266/**
267 * If type is 2 This struct is used to store the attacked peers in a DLL 267 * If type is 2 This struct is used to store the attacked peers in a DLL
@@ -492,7 +492,7 @@ static struct GNUNET_PEERINFO_Handle *peerinfo_handle;
492static struct GNUNET_PEERINFO_NotifyContext *peerinfo_notify_handle; 492static struct GNUNET_PEERINFO_NotifyContext *peerinfo_notify_handle;
493 493
494 494
495#ifdef ENABLE_MALICIOUS 495#if ENABLE_MALICIOUS
496/** 496/**
497 * Type of malicious peer 497 * Type of malicious peer
498 * 498 *
@@ -1379,6 +1379,7 @@ mq_notify_sent_cb (void *cls)
1379 if (0 == strncmp ("PUSH", pending_msg->type, 4)) 1379 if (0 == strncmp ("PUSH", pending_msg->type, 4))
1380 GNUNET_STATISTICS_update(stats, "# pushes sent", 1, GNUNET_NO); 1380 GNUNET_STATISTICS_update(stats, "# pushes sent", 1, GNUNET_NO);
1381 if (0 == strncmp ("PULL REQUEST", pending_msg->type, 12) && 1381 if (0 == strncmp ("PULL REQUEST", pending_msg->type, 12) &&
1382 NULL != map_single_hop &&
1382 GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (map_single_hop, 1383 GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (map_single_hop,
1383 &pending_msg->peer_ctx->peer_id)) 1384 &pending_msg->peer_ctx->peer_id))
1384 GNUNET_STATISTICS_update(stats, 1385 GNUNET_STATISTICS_update(stats,
@@ -2576,7 +2577,7 @@ insert_in_sampler (void *cls,
2576 * messages to it */ 2577 * messages to it */
2577 //indicate_sending_intention (peer); 2578 //indicate_sending_intention (peer);
2578 } 2579 }
2579 #ifdef TO_FILE 2580#ifdef TO_FILE
2580 sub->num_observed_peers++; 2581 sub->num_observed_peers++;
2581 GNUNET_CONTAINER_multipeermap_put 2582 GNUNET_CONTAINER_multipeermap_put
2582 (sub->observed_unique_peers, 2583 (sub->observed_unique_peers,
@@ -2590,7 +2591,7 @@ insert_in_sampler (void *cls,
2590 sub->num_observed_peers, 2591 sub->num_observed_peers,
2591 num_observed_unique_peers, 2592 num_observed_unique_peers,
2592 1.0*num_observed_unique_peers/sub->num_observed_peers) 2593 1.0*num_observed_unique_peers/sub->num_observed_peers)
2593 #endif /* TO_FILE */ 2594#endif /* TO_FILE */
2594} 2595}
2595 2596
2596 2597
@@ -2675,11 +2676,23 @@ static void
2675remove_peer (struct Sub *sub, 2676remove_peer (struct Sub *sub,
2676 const struct GNUNET_PeerIdentity *peer) 2677 const struct GNUNET_PeerIdentity *peer)
2677{ 2678{
2678 (void) View_remove_peer (sub->view, peer); 2679 (void) View_remove_peer (sub->view,
2679 CustomPeerMap_remove_peer (sub->pull_map, peer); 2680 peer);
2680 CustomPeerMap_remove_peer (sub->push_map, peer); 2681 CustomPeerMap_remove_peer (sub->pull_map,
2681 RPS_sampler_reinitialise_by_value (sub->sampler, peer); 2682 peer);
2682 destroy_peer (get_peer_ctx (sub->peer_map, peer)); 2683 CustomPeerMap_remove_peer (sub->push_map,
2684 peer);
2685 RPS_sampler_reinitialise_by_value (sub->sampler,
2686 peer);
2687 /* We want to destroy the peer now.
2688 * Sometimes, it just seems that it's already been removed from the peer_map,
2689 * so check the peer_map first. */
2690 if (GNUNET_YES == check_peer_known (sub->peer_map,
2691 peer))
2692 {
2693 destroy_peer (get_peer_ctx (sub->peer_map,
2694 peer));
2695 }
2683} 2696}
2684 2697
2685 2698
@@ -2701,15 +2714,19 @@ clean_peer (struct Sub *sub,
2701 LOG (GNUNET_ERROR_TYPE_DEBUG, 2714 LOG (GNUNET_ERROR_TYPE_DEBUG,
2702 "Going to remove send channel to peer %s\n", 2715 "Going to remove send channel to peer %s\n",
2703 GNUNET_i2s (peer)); 2716 GNUNET_i2s (peer));
2704 #ifdef ENABLE_MALICIOUS 2717 #if ENABLE_MALICIOUS
2705 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&attacked_peer, peer)) 2718 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&attacked_peer,
2706 (void) destroy_sending_channel (get_peer_ctx (sub->peer_map, peer)); 2719 peer))
2720 (void) destroy_sending_channel (get_peer_ctx (sub->peer_map,
2721 peer));
2707 #else /* ENABLE_MALICIOUS */ 2722 #else /* ENABLE_MALICIOUS */
2708 (void) destroy_sending_channel (get_peer_ctx (sub->peer_map, peer)); 2723 (void) destroy_sending_channel (get_peer_ctx (sub->peer_map,
2724 peer));
2709 #endif /* ENABLE_MALICIOUS */ 2725 #endif /* ENABLE_MALICIOUS */
2710 } 2726 }
2711 2727
2712 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (sub->peer_map, peer)) 2728 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (sub->peer_map,
2729 peer))
2713 { 2730 {
2714 /* Peer was already removed by callback on destroyed channel */ 2731 /* Peer was already removed by callback on destroyed channel */
2715 LOG (GNUNET_ERROR_TYPE_WARNING, 2732 LOG (GNUNET_ERROR_TYPE_WARNING,
@@ -2846,19 +2863,15 @@ new_sub (const struct GNUNET_HashCode *hash,
2846 { 2863 {
2847 char *tmp_filename_valid_peers; 2864 char *tmp_filename_valid_peers;
2848 char str_hash[105]; 2865 char str_hash[105];
2849 uint32_t len_filename_valid_peers; 2866
2850 2867 GNUNET_snprintf (str_hash,
2851 (void) GNUNET_snprintf (str_hash, 105, GNUNET_h2s_full (hash)); 2868 sizeof (str_hash),
2852 tmp_filename_valid_peers = GNUNET_strdup (sub->filename_valid_peers); 2869 GNUNET_h2s_full (hash));
2853 GNUNET_free (sub->filename_valid_peers); 2870 tmp_filename_valid_peers = sub->filename_valid_peers;
2854 len_filename_valid_peers = strlen (tmp_filename_valid_peers) + 105; /* Len of full hash + 1 */ 2871 GNUNET_asprintf (&sub->filename_valid_peers,
2855 sub->filename_valid_peers = GNUNET_malloc (len_filename_valid_peers); 2872 "%s%s",
2856 strncat (sub->filename_valid_peers, 2873 tmp_filename_valid_peers,
2857 tmp_filename_valid_peers, 2874 str_hash);
2858 len_filename_valid_peers);
2859 strncat (sub->filename_valid_peers,
2860 str_hash,
2861 len_filename_valid_peers);
2862 GNUNET_free (tmp_filename_valid_peers); 2875 GNUNET_free (tmp_filename_valid_peers);
2863 } 2876 }
2864 sub->peer_map = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO); 2877 sub->peer_map = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
@@ -2874,7 +2887,7 @@ new_sub (const struct GNUNET_HashCode *hash,
2874 2887
2875 /* Logging of internals */ 2888 /* Logging of internals */
2876 sub->file_name_view_log = store_prefix_file_name (&own_identity, "view"); 2889 sub->file_name_view_log = store_prefix_file_name (&own_identity, "view");
2877 #ifdef TO_FILE 2890#ifdef TO_FILE
2878 sub->file_name_observed_log = store_prefix_file_name (&own_identity, 2891 sub->file_name_observed_log = store_prefix_file_name (&own_identity,
2879 "observed"); 2892 "observed");
2880 sub->file_name_push_recv = store_prefix_file_name (&own_identity, 2893 sub->file_name_push_recv = store_prefix_file_name (&own_identity,
@@ -2884,7 +2897,7 @@ new_sub (const struct GNUNET_HashCode *hash,
2884 sub->num_observed_peers = 0; 2897 sub->num_observed_peers = 0;
2885 sub->observed_unique_peers = GNUNET_CONTAINER_multipeermap_create (1, 2898 sub->observed_unique_peers = GNUNET_CONTAINER_multipeermap_create (1,
2886 GNUNET_NO); 2899 GNUNET_NO);
2887 #endif /* TO_FILE */ 2900#endif /* TO_FILE */
2888 2901
2889 /* Set up data structures for gossip */ 2902 /* Set up data structures for gossip */
2890 sub->push_map = CustomPeerMap_create (4); 2903 sub->push_map = CustomPeerMap_create (4);
@@ -2915,8 +2928,10 @@ static void
2915destroy_sub (struct Sub *sub) 2928destroy_sub (struct Sub *sub)
2916{ 2929{
2917#ifdef TO_FILE 2930#ifdef TO_FILE
2918 char push_recv_str[1536] = ""; /* 256 * 6 (1 whitespace, 1 comma, up to 4 chars) */ 2931#define SIZE_DUMP_FILE 1536 /* 256 * 6 (1 whitespace, 1 comma, up to 4 chars) */
2919 char pull_delays_str[1536] = ""; /* 256 * 6 (1 whitespace, 1 comma, up to 4 chars) */ 2932 char push_recv_str[SIZE_DUMP_FILE + 1] = "";
2933 char pull_delays_str[SIZE_DUMP_FILE + 1] = "";
2934 char *recv_str_iter;
2920#endif /* TO_FILE */ 2935#endif /* TO_FILE */
2921 GNUNET_assert (NULL != sub); 2936 GNUNET_assert (NULL != sub);
2922 GNUNET_assert (NULL != sub->do_round_task); 2937 GNUNET_assert (NULL != sub->do_round_task);
@@ -2945,36 +2960,49 @@ destroy_sub (struct Sub *sub)
2945 sub->file_name_observed_log = NULL; 2960 sub->file_name_observed_log = NULL;
2946 2961
2947 /* Write push frequencies to disk */ 2962 /* Write push frequencies to disk */
2963 recv_str_iter = push_recv_str;
2948 for (uint32_t i = 0; i < 256; i++) 2964 for (uint32_t i = 0; i < 256; i++)
2949 { 2965 {
2950 char push_recv_str_tmp[8]; 2966 char push_recv_str_tmp[8];
2951 (void) snprintf (push_recv_str_tmp, 8, "%" PRIu32 "\n", sub->push_recv[i]); 2967
2952 (void) strncat (push_recv_str, 2968 GNUNET_snprintf (push_recv_str_tmp,
2953 push_recv_str_tmp, 2969 sizeof (push_recv_str_tmp),
2954 1535 - strnlen (push_recv_str, 1536)); 2970 "%" PRIu32 "\n",
2955 } 2971 sub->push_recv[i]);
2956 (void) strncat (push_recv_str, 2972 recv_str_iter = stpncpy (recv_str_iter,
2957 "\n", 2973 push_recv_str_tmp,
2958 1535 - strnlen (push_recv_str, 1536)); 2974 6);
2959 LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing push stats to disk\n"); 2975 }
2960 to_file_w_len (sub->file_name_push_recv, 1535, push_recv_str); 2976 (void) stpcpy (recv_str_iter,
2977 "\n");
2978 LOG (GNUNET_ERROR_TYPE_DEBUG,
2979 "Writing push stats to disk\n");
2980 to_file_w_len (sub->file_name_push_recv,
2981 SIZE_DUMP_FILE,
2982 push_recv_str);
2961 GNUNET_free (sub->file_name_push_recv); 2983 GNUNET_free (sub->file_name_push_recv);
2962 sub->file_name_push_recv = NULL; 2984 sub->file_name_push_recv = NULL;
2963 2985
2964 /* Write pull delays to disk */ 2986 /* Write pull delays to disk */
2987 recv_str_iter = pull_delays_str;
2965 for (uint32_t i = 0; i < 256; i++) 2988 for (uint32_t i = 0; i < 256; i++)
2966 { 2989 {
2967 char pull_delays_str_tmp[8]; 2990 char pull_delays_str_tmp[8];
2968 (void) snprintf (pull_delays_str_tmp, 8, "%" PRIu32 "\n", sub->pull_delays[i]); 2991
2969 (void) strncat (pull_delays_str, 2992 GNUNET_snprintf (pull_delays_str_tmp,
2970 pull_delays_str_tmp, 2993 sizeof (pull_delays_str_tmp),
2971 1535 - strnlen (pull_delays_str, 1536)); 2994 "%" PRIu32 "\n",
2972 } 2995 sub->pull_delays[i]);
2973 (void) strncat (pull_delays_str, 2996 recv_str_iter = stpncpy (recv_str_iter,
2974 "\n", 2997 pull_delays_str_tmp,
2975 1535 - strnlen (pull_delays_str, 1536)); 2998 6);
2999 }
3000 (void) stpcpy (recv_str_iter,
3001 "\n");
2976 LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing pull delays to disk\n"); 3002 LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing pull delays to disk\n");
2977 to_file_w_len (sub->file_name_pull_delays, 1535, pull_delays_str); 3003 to_file_w_len (sub->file_name_pull_delays,
3004 SIZE_DUMP_FILE,
3005 pull_delays_str);
2978 GNUNET_free (sub->file_name_pull_delays); 3006 GNUNET_free (sub->file_name_pull_delays);
2979 sub->file_name_pull_delays = NULL; 3007 sub->file_name_pull_delays = NULL;
2980 3008
@@ -3028,8 +3056,11 @@ core_connects (void *cls,
3028 (void) cls; 3056 (void) cls;
3029 (void) mq; 3057 (void) mq;
3030 3058
3031 GNUNET_CONTAINER_multipeermap_put (map_single_hop, peer, NULL, 3059 GNUNET_assert (GNUNET_YES ==
3032 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); 3060 GNUNET_CONTAINER_multipeermap_put (map_single_hop,
3061 peer,
3062 NULL,
3063 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3033 return NULL; 3064 return NULL;
3034} 3065}
3035 3066
@@ -3436,7 +3467,7 @@ handle_peer_push (void *cls,
3436 GNUNET_STATISTICS_update(stats, "# push message received", 1, GNUNET_NO); 3467 GNUNET_STATISTICS_update(stats, "# push message received", 1, GNUNET_NO);
3437 } 3468 }
3438 3469
3439 #ifdef ENABLE_MALICIOUS 3470 #if ENABLE_MALICIOUS
3440 struct AttackedPeer *tmp_att_peer; 3471 struct AttackedPeer *tmp_att_peer;
3441 3472
3442 if ( (1 == mal_type) || 3473 if ( (1 == mal_type) ||
@@ -3512,7 +3543,7 @@ handle_peer_pull_request (void *cls,
3512 } 3543 }
3513 } 3544 }
3514 3545
3515 #ifdef ENABLE_MALICIOUS 3546 #if ENABLE_MALICIOUS
3516 if (1 == mal_type 3547 if (1 == mal_type
3517 || 3 == mal_type) 3548 || 3 == mal_type)
3518 { /* Try to maximise representation */ 3549 { /* Try to maximise representation */
@@ -3606,7 +3637,7 @@ handle_peer_pull_reply (void *cls,
3606 const struct GNUNET_PeerIdentity *peers; 3637 const struct GNUNET_PeerIdentity *peers;
3607 struct Sub *sub = channel_ctx->peer_ctx->sub; 3638 struct Sub *sub = channel_ctx->peer_ctx->sub;
3608 uint32_t i; 3639 uint32_t i;
3609#ifdef ENABLE_MALICIOUS 3640#if ENABLE_MALICIOUS
3610 struct AttackedPeer *tmp_att_peer; 3641 struct AttackedPeer *tmp_att_peer;
3611#endif /* ENABLE_MALICIOUS */ 3642#endif /* ENABLE_MALICIOUS */
3612 3643
@@ -3618,7 +3649,8 @@ handle_peer_pull_reply (void *cls,
3618 "# pull reply messages received", 3649 "# pull reply messages received",
3619 1, 3650 1,
3620 GNUNET_NO); 3651 GNUNET_NO);
3621 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (map_single_hop, 3652 if (NULL != map_single_hop &&
3653 GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (map_single_hop,
3622 &channel_ctx->peer_ctx->peer_id)) 3654 &channel_ctx->peer_ctx->peer_id))
3623 { 3655 {
3624 GNUNET_STATISTICS_update (stats, 3656 GNUNET_STATISTICS_update (stats,
@@ -3628,7 +3660,7 @@ handle_peer_pull_reply (void *cls,
3628 } 3660 }
3629 } 3661 }
3630 3662
3631 #ifdef ENABLE_MALICIOUS 3663 #if ENABLE_MALICIOUS
3632 // We shouldn't even receive pull replies as we're not sending 3664 // We shouldn't even receive pull replies as we're not sending
3633 if (2 == mal_type) 3665 if (2 == mal_type)
3634 { 3666 {
@@ -3649,7 +3681,7 @@ handle_peer_pull_reply (void *cls,
3649 i, 3681 i,
3650 GNUNET_i2s (&peers[i])); 3682 GNUNET_i2s (&peers[i]));
3651 3683
3652 #ifdef ENABLE_MALICIOUS 3684 #if ENABLE_MALICIOUS
3653 if ((NULL != att_peer_set) && 3685 if ((NULL != att_peer_set) &&
3654 (1 == mal_type || 3 == mal_type)) 3686 (1 == mal_type || 3 == mal_type))
3655 { /* Add attacked peer to local list */ 3687 { /* Add attacked peer to local list */
@@ -3670,25 +3702,30 @@ handle_peer_pull_reply (void *cls,
3670 } 3702 }
3671 #endif /* ENABLE_MALICIOUS */ 3703 #endif /* ENABLE_MALICIOUS */
3672 /* Make sure we 'know' about this peer */ 3704 /* Make sure we 'know' about this peer */
3673 (void) insert_peer (channel_ctx->peer_ctx->sub, &peers[i]); 3705 (void) insert_peer (channel_ctx->peer_ctx->sub,
3706 &peers[i]);
3674 3707
3675 if (GNUNET_YES == check_peer_valid (channel_ctx->peer_ctx->sub->valid_peers, 3708 if (GNUNET_YES == check_peer_valid (channel_ctx->peer_ctx->sub->valid_peers,
3676 &peers[i])) 3709 &peers[i]))
3677 { 3710 {
3678 CustomPeerMap_put (channel_ctx->peer_ctx->sub->pull_map, &peers[i]); 3711 CustomPeerMap_put (channel_ctx->peer_ctx->sub->pull_map,
3712 &peers[i]);
3679 } 3713 }
3680 else 3714 else
3681 { 3715 {
3682 schedule_operation (channel_ctx->peer_ctx, 3716 schedule_operation (channel_ctx->peer_ctx,
3683 insert_in_pull_map, 3717 insert_in_pull_map,
3684 channel_ctx->peer_ctx->sub); /* cls */ 3718 channel_ctx->peer_ctx->sub); /* cls */
3685 (void) issue_peer_online_check (channel_ctx->peer_ctx->sub, &peers[i]); 3719 (void) issue_peer_online_check (channel_ctx->peer_ctx->sub,
3720 &peers[i]);
3686 } 3721 }
3687 } 3722 }
3688 3723
3689 UNSET_PEER_FLAG (get_peer_ctx (channel_ctx->peer_ctx->sub->peer_map, sender), 3724 UNSET_PEER_FLAG (get_peer_ctx (channel_ctx->peer_ctx->sub->peer_map,
3725 sender),
3690 Peers_PULL_REPLY_PENDING); 3726 Peers_PULL_REPLY_PENDING);
3691 clean_peer (channel_ctx->peer_ctx->sub, sender); 3727 clean_peer (channel_ctx->peer_ctx->sub,
3728 sender);
3692 3729
3693 GNUNET_break_op (check_peer_known (channel_ctx->peer_ctx->sub->peer_map, 3730 GNUNET_break_op (check_peer_known (channel_ctx->peer_ctx->sub->peer_map,
3694 sender)); 3731 sender));
@@ -3812,7 +3849,7 @@ send_push (struct PeerContext *peer_ctx)
3812} 3849}
3813 3850
3814 3851
3815#ifdef ENABLE_MALICIOUS 3852#if ENABLE_MALICIOUS
3816 3853
3817 3854
3818/** 3855/**
@@ -4534,7 +4571,7 @@ shutdown_task (void *cls)
4534 } 4571 }
4535 GNUNET_CADET_disconnect (cadet_handle); 4572 GNUNET_CADET_disconnect (cadet_handle);
4536 cadet_handle = NULL; 4573 cadet_handle = NULL;
4537#ifdef ENABLE_MALICIOUS 4574#if ENABLE_MALICIOUS
4538 struct AttackedPeer *tmp_att_peer; 4575 struct AttackedPeer *tmp_att_peer;
4539 GNUNET_array_grow (mal_peers, 4576 GNUNET_array_grow (mal_peers,
4540 num_mal_peers, 4577 num_mal_peers,
@@ -4647,7 +4684,7 @@ run (void *cls,
4647 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4684 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4648 "STARTING SERVICE (rps) for peer [%s]\n", 4685 "STARTING SERVICE (rps) for peer [%s]\n",
4649 GNUNET_i2s (&own_identity)); 4686 GNUNET_i2s (&own_identity));
4650#ifdef ENABLE_MALICIOUS 4687#if ENABLE_MALICIOUS
4651 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 4688 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4652 "Malicious execution compiled in.\n"); 4689 "Malicious execution compiled in.\n");
4653#endif /* ENABLE_MALICIOUS */ 4690#endif /* ENABLE_MALICIOUS */
@@ -4740,7 +4777,7 @@ GNUNET_SERVICE_MAIN
4740 GNUNET_MESSAGE_TYPE_RPS_CS_SEED, 4777 GNUNET_MESSAGE_TYPE_RPS_CS_SEED,
4741 struct GNUNET_RPS_CS_SeedMessage, 4778 struct GNUNET_RPS_CS_SeedMessage,
4742 NULL), 4779 NULL),
4743#ifdef ENABLE_MALICIOUS 4780#if ENABLE_MALICIOUS
4744 GNUNET_MQ_hd_var_size (client_act_malicious, 4781 GNUNET_MQ_hd_var_size (client_act_malicious,
4745 GNUNET_MESSAGE_TYPE_RPS_ACT_MALICIOUS, 4782 GNUNET_MESSAGE_TYPE_RPS_ACT_MALICIOUS,
4746 struct GNUNET_RPS_CS_ActMaliciousMessage, 4783 struct GNUNET_RPS_CS_ActMaliciousMessage,
diff --git a/src/rps/gnunet-service-rps_custommap.c b/src/rps/gnunet-service-rps_custommap.c
index 18a433d6b..d3cc8d104 100644
--- a/src/rps/gnunet-service-rps_custommap.c
+++ b/src/rps/gnunet-service-rps_custommap.c
@@ -82,7 +82,8 @@ CustomPeerMap_create (unsigned int len)
82 82
83 c_peer_map = GNUNET_new (struct CustomPeerMap); 83 c_peer_map = GNUNET_new (struct CustomPeerMap);
84 c_peer_map->hash_map = GNUNET_CONTAINER_multihashmap32_create (len); 84 c_peer_map->hash_map = GNUNET_CONTAINER_multihashmap32_create (len);
85 c_peer_map->peer_map = GNUNET_CONTAINER_multipeermap_create (len, GNUNET_NO); 85 c_peer_map->peer_map = GNUNET_CONTAINER_multipeermap_create (len,
86 GNUNET_NO);
86 return c_peer_map; 87 return c_peer_map;
87} 88}
88 89
@@ -129,10 +130,16 @@ CustomPeerMap_put (const struct CustomPeerMap *c_peer_map,
129 p = GNUNET_new (struct GNUNET_PeerIdentity); 130 p = GNUNET_new (struct GNUNET_PeerIdentity);
130 *p = *peer; 131 *p = *peer;
131 GNUNET_assert (p != peer); 132 GNUNET_assert (p != peer);
132 GNUNET_assert (0 == memcmp (p, peer, sizeof(struct GNUNET_PeerIdentity))); 133 GNUNET_assert (0 == memcmp (p,
133 GNUNET_CONTAINER_multipeermap_put (c_peer_map->peer_map, p, index, 134 peer,
135 sizeof(struct GNUNET_PeerIdentity)));
136 GNUNET_CONTAINER_multipeermap_put (c_peer_map->peer_map,
137 p,
138 index,
134 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); 139 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
135 GNUNET_CONTAINER_multihashmap32_put (c_peer_map->hash_map, *index, p, 140 GNUNET_CONTAINER_multihashmap32_put (c_peer_map->hash_map,
141 *index,
142 p,
136 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); 143 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
137 GNUNET_assert (GNUNET_CONTAINER_multihashmap32_size (c_peer_map->hash_map) == 144 GNUNET_assert (GNUNET_CONTAINER_multihashmap32_size (c_peer_map->hash_map) ==
138 GNUNET_CONTAINER_multipeermap_size (c_peer_map->peer_map)); 145 GNUNET_CONTAINER_multipeermap_size (c_peer_map->peer_map));
@@ -194,30 +201,38 @@ CustomPeerMap_remove_peer (const struct CustomPeerMap *c_peer_map,
194 uint32_t *last_index; 201 uint32_t *last_index;
195 struct GNUNET_PeerIdentity *last_p; 202 struct GNUNET_PeerIdentity *last_p;
196 203
197 if (GNUNET_NO == CustomPeerMap_contains_peer (c_peer_map, peer)) 204 if (GNUNET_NO == CustomPeerMap_contains_peer (c_peer_map,
205 peer))
198 { 206 {
199 return GNUNET_NO; 207 return GNUNET_NO;
200 } 208 }
201 index = CustomPeerMap_get_index_pointer (c_peer_map, peer); 209 index = CustomPeerMap_get_index_pointer (c_peer_map,
210 peer);
202 GNUNET_assert (*index < CustomPeerMap_size (c_peer_map)); 211 GNUNET_assert (*index < CustomPeerMap_size (c_peer_map));
203 /* Need to get the pointer stored in the hashmap to free it */ 212 /* Need to get the pointer stored in the hashmap to free it */
204 p = GNUNET_CONTAINER_multihashmap32_get (c_peer_map->hash_map, *index); 213 p = GNUNET_CONTAINER_multihashmap32_get (c_peer_map->hash_map,
214 *index);
205 GNUNET_assert (NULL != p); 215 GNUNET_assert (NULL != p);
206 GNUNET_CONTAINER_multihashmap32_remove_all (c_peer_map->hash_map, *index); 216 GNUNET_CONTAINER_multihashmap32_remove_all (c_peer_map->hash_map,
217 *index);
207 // TODO wrong peerid? 218 // TODO wrong peerid?
208 GNUNET_CONTAINER_multipeermap_remove_all (c_peer_map->peer_map, peer); 219 GNUNET_CONTAINER_multipeermap_remove_all (c_peer_map->peer_map,
220 peer);
209 if (*index != CustomPeerMap_size (c_peer_map)) 221 if (*index != CustomPeerMap_size (c_peer_map))
210 { /* fill 'gap' with peer at last index */ 222 { /* fill 'gap' with peer at last index */
211 last_p = 223 last_p =
212 GNUNET_CONTAINER_multihashmap32_get (c_peer_map->hash_map, 224 GNUNET_CONTAINER_multihashmap32_get (c_peer_map->hash_map,
213 CustomPeerMap_size (c_peer_map)); 225 CustomPeerMap_size (c_peer_map));
214 GNUNET_assert (NULL != last_p); 226 GNUNET_assert (NULL != last_p);
215 last_index = GNUNET_CONTAINER_multipeermap_get (c_peer_map->peer_map, last_p); 227 last_index = GNUNET_CONTAINER_multipeermap_get (c_peer_map->peer_map,
228 last_p);
216 GNUNET_assert (NULL != last_index); 229 GNUNET_assert (NULL != last_index);
217 GNUNET_assert (CustomPeerMap_size (c_peer_map) == *last_index); 230 GNUNET_assert (CustomPeerMap_size (c_peer_map) == *last_index);
218 GNUNET_CONTAINER_multihashmap32_put (c_peer_map->hash_map, *index, last_p, 231 GNUNET_CONTAINER_multihashmap32_put (c_peer_map->hash_map,
232 *index, last_p,
219 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); 233 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
220 GNUNET_CONTAINER_multihashmap32_remove_all (c_peer_map->hash_map, *last_index); 234 GNUNET_CONTAINER_multihashmap32_remove_all (c_peer_map->hash_map,
235 *last_index);
221 *last_index = *index; 236 *last_index = *index;
222 } 237 }
223 GNUNET_free (index); 238 GNUNET_free (index);
diff --git a/src/rps/profiler_rps.conf b/src/rps/profiler_rps.conf
index 1369d3fdf..6049da5a0 100644
--- a/src/rps/profiler_rps.conf
+++ b/src/rps/profiler_rps.conf
@@ -83,8 +83,7 @@ BLUETOOTH_QUOTA_OUT = unlimited
83DISABLE_TRY_CONNECT = YES 83DISABLE_TRY_CONNECT = YES
84 84
85[cadet] 85[cadet]
86#OPTIONS=-l /tmp/rps_profiler_logs/cadet-[]-%Y-%m-%d.log 86OPTIONS=-l /tmp/rps_profiler_logs/cadet-[]-%Y-%m-%d.log
87#PREFIX = valgrind
88 87
89#[arm] 88#[arm]
90#GLOBAL_POSTFIX=-l /tmp/rps_profiler_logs/other-[]-%Y-%m-%d.log 89#GLOBAL_POSTFIX=-l /tmp/rps_profiler_logs/other-[]-%Y-%m-%d.log
diff --git a/src/rps/rps-test_util.c b/src/rps/rps-test_util.c
index 7f54feca1..85829f247 100644
--- a/src/rps/rps-test_util.c
+++ b/src/rps/rps-test_util.c
@@ -80,41 +80,36 @@ get_file_handle (const char *name)
80 if (NULL == open_files) 80 if (NULL == open_files)
81 { 81 {
82 open_files = GNUNET_CONTAINER_multihashmap_create (16, 82 open_files = GNUNET_CONTAINER_multihashmap_create (16,
83 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); 83 GNUNET_NO);
84 LOG (GNUNET_ERROR_TYPE_DEBUG,
85 "Created map of open files.\n");
84 } 86 }
85 GNUNET_CRYPTO_hash (name, 87 GNUNET_CRYPTO_hash (name,
86 strnlen (name, 88 strlen (name),
87 512),
88 &hash); 89 &hash);
89 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (open_files, 90 if (NULL != (fh = GNUNET_CONTAINER_multihashmap_get (open_files,
90 &hash)) 91 &hash)))
91 {
92 fh = GNUNET_DISK_file_open (name,
93 GNUNET_DISK_OPEN_WRITE |
94 GNUNET_DISK_OPEN_CREATE |
95 GNUNET_DISK_OPEN_APPEND,
96 GNUNET_DISK_PERM_USER_READ |
97 GNUNET_DISK_PERM_USER_WRITE |
98 GNUNET_DISK_PERM_GROUP_READ);
99 if (NULL == fh)
100 {
101 LOG (GNUNET_ERROR_TYPE_ERROR,
102 "Opening file `%s' failed.\n",
103 name);
104 GNUNET_assert (0);
105 }
106 GNUNET_CONTAINER_multihashmap_put (open_files,
107 &hash,
108 fh,
109 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
110 return fh; 92 return fh;
111 } 93 fh = GNUNET_DISK_file_open (name,
112 else 94 GNUNET_DISK_OPEN_WRITE |
95 GNUNET_DISK_OPEN_CREATE |
96 GNUNET_DISK_OPEN_APPEND,
97 GNUNET_DISK_PERM_USER_READ |
98 GNUNET_DISK_PERM_USER_WRITE |
99 GNUNET_DISK_PERM_GROUP_READ);
100 if (NULL == fh)
113 { 101 {
114 fh = GNUNET_CONTAINER_multihashmap_get (open_files, 102 LOG (GNUNET_ERROR_TYPE_ERROR,
115 &hash); 103 "Opening file `%s' failed.\n",
116 return fh; 104 name);
105 GNUNET_assert (0);
117 } 106 }
107 GNUNET_assert (GNUNET_YES ==
108 GNUNET_CONTAINER_multihashmap_put (open_files,
109 &hash,
110 fh,
111 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
112 return fh;
118} 113}
119 114
120 115
@@ -162,6 +157,7 @@ close_all_files ()
162 close_files_iter, 157 close_files_iter,
163 NULL); 158 NULL);
164 GNUNET_CONTAINER_multihashmap_destroy (open_files); 159 GNUNET_CONTAINER_multihashmap_destroy (open_files);
160 open_files = NULL;
165 return ret; 161 return ret;
166} 162}
167 163
@@ -491,6 +487,7 @@ static int ensure_folder_exist (void)
491 } 487 }
492 if (GNUNET_YES != GNUNET_DISK_directory_test ("/tmp/rps/", GNUNET_NO)) 488 if (GNUNET_YES != GNUNET_DISK_directory_test ("/tmp/rps/", GNUNET_NO))
493 { 489 {
490 LOG (GNUNET_ERROR_TYPE_ERROR, "Could not create directory `/tmp/rps'\n");
494 return GNUNET_SYSERR; 491 return GNUNET_SYSERR;
495 } 492 }
496 return GNUNET_YES; 493 return GNUNET_YES;
diff --git a/src/rps/rps-test_util.h b/src/rps/rps-test_util.h
index cf15a9909..484d0f7da 100644
--- a/src/rps/rps-test_util.h
+++ b/src/rps/rps-test_util.h
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -28,7 +28,7 @@
28#ifndef RPS_TEST_UTIL_H 28#ifndef RPS_TEST_UTIL_H
29#define RPS_TEST_UTIL_H 29#define RPS_TEST_UTIL_H
30 30
31#define TO_FILE 1 31#define TO_FILE 0
32 32
33 33
34char * 34char *
diff --git a/src/rps/rps.h b/src/rps/rps.h
index ef968ffbb..5bfef93b0 100644
--- a/src/rps/rps.h
+++ b/src/rps/rps.h
@@ -79,7 +79,7 @@ struct GNUNET_RPS_CS_SeedMessage
79 /* Followed by num_peers * GNUNET_PeerIdentity */ 79 /* Followed by num_peers * GNUNET_PeerIdentity */
80}; 80};
81 81
82#ifdef ENABLE_MALICIOUS 82#if ENABLE_MALICIOUS
83/** 83/**
84 * Message from client to service to turn service malicious. 84 * Message from client to service to turn service malicious.
85 */ 85 */
diff --git a/src/rps/rps_api.c b/src/rps/rps_api.c
index 6fac4cf6f..d0b241a2b 100644
--- a/src/rps/rps_api.c
+++ b/src/rps/rps_api.c
@@ -806,7 +806,7 @@ GNUNET_RPS_seed_ids (struct GNUNET_RPS_Handle *h,
806} 806}
807 807
808 808
809#ifdef ENABLE_MALICIOUS 809#if ENABLE_MALICIOUS
810/** 810/**
811 * Turn RPS service to act malicious. 811 * Turn RPS service to act malicious.
812 * 812 *
diff --git a/src/rps/test_rps.c b/src/rps/test_rps.c
index 126cc5dec..26066bf10 100644
--- a/src/rps/test_rps.c
+++ b/src/rps/test_rps.c
@@ -1357,7 +1357,7 @@ static void mal_init_peer (struct RPSPeer *rps_peer)
1357static void 1357static void
1358mal_pre (struct RPSPeer *rps_peer, struct GNUNET_RPS_Handle *h) 1358mal_pre (struct RPSPeer *rps_peer, struct GNUNET_RPS_Handle *h)
1359{ 1359{
1360 #ifdef ENABLE_MALICIOUS 1360 #if ENABLE_MALICIOUS
1361 uint32_t num_mal_peers; 1361 uint32_t num_mal_peers;
1362 1362
1363 GNUNET_assert ( (1 >= portion) && 1363 GNUNET_assert ( (1 >= portion) &&
@@ -1388,7 +1388,7 @@ mal_cb (struct RPSPeer *rps_peer)
1388 return; 1388 return;
1389 } 1389 }
1390 1390
1391 #ifdef ENABLE_MALICIOUS 1391 #if ENABLE_MALICIOUS
1392 GNUNET_assert ( (1 >= portion) && 1392 GNUNET_assert ( (1 >= portion) &&
1393 (0 < portion) ); 1393 (0 < portion) );
1394 num_mal_peers = round (portion * num_peers); 1394 num_mal_peers = round (portion * num_peers);
diff --git a/src/rps/test_rps.conf b/src/rps/test_rps.conf
index 1555a71a5..c22113af5 100644
--- a/src/rps/test_rps.conf
+++ b/src/rps/test_rps.conf
@@ -82,7 +82,7 @@ DISABLE_TRY_CONNECT = YES
82 82
83[cadet] 83[cadet]
84#OPTIONS=-l /tmp/rps_profiler_logs/cadet-[]-%Y-%m-%d.log 84#OPTIONS=-l /tmp/rps_profiler_logs/cadet-[]-%Y-%m-%d.log
85#PREFIX = valgrind 85#PREFIX = valgrind --log-file=/tmp/rps/valgrind_gnunet-service-cadet_%p
86 86
87#[arm] 87#[arm]
88#GLOBAL_POSTFIX=-l /tmp/rps_profiler_logs/other-[]-%Y-%m-%d.log 88#GLOBAL_POSTFIX=-l /tmp/rps_profiler_logs/other-[]-%Y-%m-%d.log
diff --git a/src/secretsharing/gnunet-service-secretsharing.c b/src/secretsharing/gnunet-service-secretsharing.c
index d4c01fedb..1ffde0436 100644
--- a/src/secretsharing/gnunet-service-secretsharing.c
+++ b/src/secretsharing/gnunet-service-secretsharing.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -898,7 +898,9 @@ restore_fair (const struct GNUNET_CRYPTO_PaillierPublicKey *ppub,
898 GNUNET_assert (NULL != (big_b = gcry_mpi_new (0))); 898 GNUNET_assert (NULL != (big_b = gcry_mpi_new (0)));
899 899
900 // a = (N,0)^T 900 // a = (N,0)^T
901 GNUNET_CRYPTO_mpi_scan_unsigned (&a_1, ppub, sizeof (struct GNUNET_CRYPTO_PaillierPublicKey)); 901 GNUNET_CRYPTO_mpi_scan_unsigned (&a_1,
902 ppub,
903 sizeof (struct GNUNET_CRYPTO_PaillierPublicKey));
902 GNUNET_assert (NULL != (a_2 = gcry_mpi_new (0))); 904 GNUNET_assert (NULL != (a_2 = gcry_mpi_new (0)));
903 gcry_mpi_set_ui (a_2, 0); 905 gcry_mpi_set_ui (a_2, 0);
904 // b = (x,1)^T 906 // b = (x,1)^T
@@ -957,15 +959,9 @@ restore_fair (const struct GNUNET_CRYPTO_PaillierPublicKey *ppub,
957 gcry_mpi_set (big_b, big_t); 959 gcry_mpi_set (big_b, big_t);
958 } 960 }
959 961
960 { 962 gcry_mpi_set (xres, b_2);
961 gcry_mpi_t paillier_n; 963 gcry_mpi_invm (xres, xres, elgamal_q);
962 964 gcry_mpi_mulm (xres, xres, b_1, elgamal_q);
963 GNUNET_CRYPTO_mpi_scan_unsigned (&paillier_n, ppub, sizeof (struct GNUNET_CRYPTO_PaillierPublicKey));
964
965 gcry_mpi_set (xres, b_2);
966 gcry_mpi_invm (xres, xres, elgamal_q);
967 gcry_mpi_mulm (xres, xres, b_1, elgamal_q);
968 }
969 965
970 gcry_mpi_release (a_1); 966 gcry_mpi_release (a_1);
971 gcry_mpi_release (a_2); 967 gcry_mpi_release (a_2);
@@ -984,7 +980,8 @@ restore_fair (const struct GNUNET_CRYPTO_PaillierPublicKey *ppub,
984 980
985 981
986static void 982static void
987get_fair_encryption_challenge (const struct GNUNET_SECRETSHARING_FairEncryption *fe, gcry_mpi_t e) 983get_fair_encryption_challenge (const struct GNUNET_SECRETSHARING_FairEncryption *fe,
984 gcry_mpi_t *e)
988{ 985{
989 struct { 986 struct {
990 struct GNUNET_CRYPTO_PaillierCiphertext c; 987 struct GNUNET_CRYPTO_PaillierCiphertext c;
@@ -994,18 +991,27 @@ get_fair_encryption_challenge (const struct GNUNET_SECRETSHARING_FairEncryption
994 } hash_data; 991 } hash_data;
995 struct GNUNET_HashCode e_hash; 992 struct GNUNET_HashCode e_hash;
996 993
994 memset (&hash_data,
995 0,
996 sizeof (hash_data));
997 GNUNET_memcpy (&hash_data.c, &fe->c, sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)); 997 GNUNET_memcpy (&hash_data.c, &fe->c, sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
998 GNUNET_memcpy (&hash_data.h, &fe->h, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8); 998 GNUNET_memcpy (&hash_data.h, &fe->h, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
999 GNUNET_memcpy (&hash_data.t1, &fe->t1, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8); 999 GNUNET_memcpy (&hash_data.t1, &fe->t1, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
1000 GNUNET_memcpy (&hash_data.t2, &fe->t2, GNUNET_CRYPTO_PAILLIER_BITS * 2 / 8); 1000 GNUNET_memcpy (&hash_data.t2, &fe->t2, GNUNET_CRYPTO_PAILLIER_BITS * 2 / 8);
1001 1001 GNUNET_CRYPTO_hash (&hash_data,
1002 GNUNET_CRYPTO_mpi_scan_unsigned (&e, &e_hash, sizeof (struct GNUNET_HashCode)); 1002 sizeof (hash_data),
1003 gcry_mpi_mod (e, e, elgamal_q); 1003 &e_hash);
1004 /* This allocates "e" */
1005 GNUNET_CRYPTO_mpi_scan_unsigned (e,
1006 &e_hash,
1007 sizeof (struct GNUNET_HashCode));
1008 gcry_mpi_mod (*e, *e, elgamal_q);
1004} 1009}
1005 1010
1006 1011
1007static int 1012static int
1008verify_fair (const struct GNUNET_CRYPTO_PaillierPublicKey *ppub, const struct GNUNET_SECRETSHARING_FairEncryption *fe) 1013verify_fair (const struct GNUNET_CRYPTO_PaillierPublicKey *ppub,
1014 const struct GNUNET_SECRETSHARING_FairEncryption *fe)
1009{ 1015{
1010 gcry_mpi_t n; 1016 gcry_mpi_t n;
1011 gcry_mpi_t n_sq; 1017 gcry_mpi_t n_sq;
@@ -1023,11 +1029,13 @@ verify_fair (const struct GNUNET_CRYPTO_PaillierPublicKey *ppub, const struct GN
1023 GNUNET_assert (NULL != (n_sq = gcry_mpi_new (0))); 1029 GNUNET_assert (NULL != (n_sq = gcry_mpi_new (0)));
1024 GNUNET_assert (NULL != (tmp1 = gcry_mpi_new (0))); 1030 GNUNET_assert (NULL != (tmp1 = gcry_mpi_new (0)));
1025 GNUNET_assert (NULL != (tmp2 = gcry_mpi_new (0))); 1031 GNUNET_assert (NULL != (tmp2 = gcry_mpi_new (0)));
1026 GNUNET_assert (NULL != (e = gcry_mpi_new (0)));
1027 1032
1028 get_fair_encryption_challenge (fe, e); 1033 get_fair_encryption_challenge (fe,
1034 &e /* this allocates e */);
1029 1035
1030 GNUNET_CRYPTO_mpi_scan_unsigned (&n, ppub, sizeof (struct GNUNET_CRYPTO_PaillierPublicKey)); 1036 GNUNET_CRYPTO_mpi_scan_unsigned (&n,
1037 ppub,
1038 sizeof (struct GNUNET_CRYPTO_PaillierPublicKey));
1031 GNUNET_CRYPTO_mpi_scan_unsigned (&t1, fe->t1, GNUNET_CRYPTO_PAILLIER_BITS / 8); 1039 GNUNET_CRYPTO_mpi_scan_unsigned (&t1, fe->t1, GNUNET_CRYPTO_PAILLIER_BITS / 8);
1032 GNUNET_CRYPTO_mpi_scan_unsigned (&z, fe->z, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8); 1040 GNUNET_CRYPTO_mpi_scan_unsigned (&z, fe->z, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
1033 GNUNET_CRYPTO_mpi_scan_unsigned (&y, fe->h, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8); 1041 GNUNET_CRYPTO_mpi_scan_unsigned (&y, fe->h, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8);
@@ -1096,7 +1104,9 @@ cleanup:
1096 * @param[out] fe the fair encryption 1104 * @param[out] fe the fair encryption
1097 */ 1105 */
1098static void 1106static void
1099encrypt_fair (gcry_mpi_t v, const struct GNUNET_CRYPTO_PaillierPublicKey *ppub, struct GNUNET_SECRETSHARING_FairEncryption *fe) 1107encrypt_fair (gcry_mpi_t v,
1108 const struct GNUNET_CRYPTO_PaillierPublicKey *ppub,
1109 struct GNUNET_SECRETSHARING_FairEncryption *fe)
1100{ 1110{
1101 gcry_mpi_t r; 1111 gcry_mpi_t r;
1102 gcry_mpi_t s; 1112 gcry_mpi_t s;
@@ -1111,6 +1121,7 @@ encrypt_fair (gcry_mpi_t v, const struct GNUNET_CRYPTO_PaillierPublicKey *ppub,
1111 gcry_mpi_t Y; 1121 gcry_mpi_t Y;
1112 gcry_mpi_t G; 1122 gcry_mpi_t G;
1113 gcry_mpi_t h; 1123 gcry_mpi_t h;
1124
1114 GNUNET_assert (NULL != (r = gcry_mpi_new (0))); 1125 GNUNET_assert (NULL != (r = gcry_mpi_new (0)));
1115 GNUNET_assert (NULL != (s = gcry_mpi_new (0))); 1126 GNUNET_assert (NULL != (s = gcry_mpi_new (0)));
1116 GNUNET_assert (NULL != (t1 = gcry_mpi_new (0))); 1127 GNUNET_assert (NULL != (t1 = gcry_mpi_new (0)));
@@ -1118,13 +1129,14 @@ encrypt_fair (gcry_mpi_t v, const struct GNUNET_CRYPTO_PaillierPublicKey *ppub,
1118 GNUNET_assert (NULL != (z = gcry_mpi_new (0))); 1129 GNUNET_assert (NULL != (z = gcry_mpi_new (0)));
1119 GNUNET_assert (NULL != (w = gcry_mpi_new (0))); 1130 GNUNET_assert (NULL != (w = gcry_mpi_new (0)));
1120 GNUNET_assert (NULL != (n_sq = gcry_mpi_new (0))); 1131 GNUNET_assert (NULL != (n_sq = gcry_mpi_new (0)));
1121 GNUNET_assert (NULL != (e = gcry_mpi_new (0)));
1122 GNUNET_assert (NULL != (u = gcry_mpi_new (0))); 1132 GNUNET_assert (NULL != (u = gcry_mpi_new (0)));
1123 GNUNET_assert (NULL != (Y = gcry_mpi_new (0))); 1133 GNUNET_assert (NULL != (Y = gcry_mpi_new (0)));
1124 GNUNET_assert (NULL != (G = gcry_mpi_new (0))); 1134 GNUNET_assert (NULL != (G = gcry_mpi_new (0)));
1125 GNUNET_assert (NULL != (h = gcry_mpi_new (0))); 1135 GNUNET_assert (NULL != (h = gcry_mpi_new (0)));
1126 1136
1127 GNUNET_CRYPTO_mpi_scan_unsigned (&n, ppub, sizeof (struct GNUNET_CRYPTO_PaillierPublicKey)); 1137 GNUNET_CRYPTO_mpi_scan_unsigned (&n,
1138 ppub,
1139 sizeof (struct GNUNET_CRYPTO_PaillierPublicKey));
1128 gcry_mpi_mul (n_sq, n, n); 1140 gcry_mpi_mul (n_sq, n, n);
1129 gcry_mpi_add_ui (G, n, 1); 1141 gcry_mpi_add_ui (G, n, 1);
1130 1142
@@ -1170,8 +1182,8 @@ encrypt_fair (gcry_mpi_t v, const struct GNUNET_CRYPTO_PaillierPublicKey *ppub,
1170 GNUNET_CRYPTO_PAILLIER_BITS * 2 / 8, 1182 GNUNET_CRYPTO_PAILLIER_BITS * 2 / 8,
1171 t2); 1183 t2);
1172 1184
1173 1185 get_fair_encryption_challenge (fe,
1174 get_fair_encryption_challenge (fe, e); 1186 &e /* This allocates "e" */);
1175 1187
1176 // compute z 1188 // compute z
1177 gcry_mpi_mul (z, e, v); 1189 gcry_mpi_mul (z, e, v);
diff --git a/src/secretsharing/secretsharing.conf.in b/src/secretsharing/secretsharing.conf.in
index bd8da6177..df8566abd 100644
--- a/src/secretsharing/secretsharing.conf.in
+++ b/src/secretsharing/secretsharing.conf.in
@@ -8,8 +8,9 @@ ACCEPT_FROM6 = ::1;
8UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-secretsharing.sock 8UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-secretsharing.sock
9UNIX_MATCH_UID = YES 9UNIX_MATCH_UID = YES
10UNIX_MATCH_GID = YES 10UNIX_MATCH_GID = YES
11# PREFIX = valgrind --leak-check=yes
11# DISABLE_SOCKET_FORWARDING = NO 12# DISABLE_SOCKET_FORWARDING = NO
12# USERNAME = 13# USERNAME =
13# MAXBUF = 14# MAXBUF =
14# TIMEOUT = 15# TIMEOUT =
15# DISABLEV6 = 16# DISABLEV6 =
diff --git a/src/secretsharing/test_secretsharing.conf b/src/secretsharing/test_secretsharing.conf
index 3391c88db..7c8e45480 100644
--- a/src/secretsharing/test_secretsharing.conf
+++ b/src/secretsharing/test_secretsharing.conf
@@ -34,3 +34,7 @@ RETURN_LOCAL_ADDRESSES = YES
34[nse] 34[nse]
35START_ON_DEMAND = NO 35START_ON_DEMAND = NO
36 36
37
38[rps]
39START_ON_DEMAND = NO
40IMMEDIATE_START = NO
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
diff --git a/src/sq/sq.c b/src/sq/sq.c
index 36200aa26..e74071b81 100644
--- a/src/sq/sq.c
+++ b/src/sq/sq.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
diff --git a/src/testbed/test_testbed_api_template.conf b/src/testbed/test_testbed_api_template.conf
index 381c1bd85..43ae06f81 100644
--- a/src/testbed/test_testbed_api_template.conf
+++ b/src/testbed/test_testbed_api_template.conf
@@ -43,3 +43,7 @@ RETURN_LOCAL_ADDRESSES = YES
43 43
44[peerinfo] 44[peerinfo]
45NO_IO = YES 45NO_IO = YES
46
47[rps]
48START_ON_DEMAND = NO
49IMMEDIATE_START = NO
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am
index 727bfb134..39e5f1574 100644
--- a/src/testing/Makefile.am
+++ b/src/testing/Makefile.am
@@ -95,4 +95,5 @@ test_testing_sharedservices_LDADD = \
95 $(top_builddir)/src/util/libgnunetutil.la 95 $(top_builddir)/src/util/libgnunetutil.la
96 96
97EXTRA_DIST = \ 97EXTRA_DIST = \
98 test_testing_defaults.conf 98 test_testing_defaults.conf \
99 test_testing_sharedservices.conf
diff --git a/src/testing/test_testing_defaults.conf b/src/testing/test_testing_defaults.conf
index e6a18bc86..2e7c39113 100644
--- a/src/testing/test_testing_defaults.conf
+++ b/src/testing/test_testing_defaults.conf
@@ -19,3 +19,7 @@ INTERNAL_ADDRESS = 127.0.0.1
19EXTERNAL_ADDRESS = 127.0.0.1 19EXTERNAL_ADDRESS = 127.0.0.1
20USE_LOCALADDR = NO 20USE_LOCALADDR = NO
21 21
22
23[rps]
24START_ON_DEMAND = NO
25IMMEDIATE_START = NO
diff --git a/src/testing/test_testing_sharedservices.conf b/src/testing/test_testing_sharedservices.conf
index 24ce1b358..92eac7e71 100644
--- a/src/testing/test_testing_sharedservices.conf
+++ b/src/testing/test_testing_sharedservices.conf
@@ -24,3 +24,7 @@ INTERNAL_ADDRESS = 127.0.0.1
24EXTERNAL_ADDRESS = 127.0.0.1 24EXTERNAL_ADDRESS = 127.0.0.1
25USE_LOCALADDR = NO 25USE_LOCALADDR = NO
26 26
27
28[rps]
29START_ON_DEMAND = NO
30IMMEDIATE_START = NO
diff --git a/src/testing/testing.c b/src/testing/testing.c
index b34815364..7dbd97294 100644
--- a/src/testing/testing.c
+++ b/src/testing/testing.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -786,7 +786,7 @@ update_config (void *cls,
786 struct UpdateContext *uc = cls; 786 struct UpdateContext *uc = cls;
787 unsigned int ival; 787 unsigned int ival;
788 char cval[12]; 788 char cval[12];
789 char uval[128]; 789 char uval[PATH_MAX];
790 char *single_variable; 790 char *single_variable;
791 char *per_host_variable; 791 char *per_host_variable;
792 unsigned long long num_per_host; 792 unsigned long long num_per_host;
@@ -839,7 +839,9 @@ update_config (void *cls,
839 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing", 839 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
840 single_variable)) 840 single_variable))
841 { 841 {
842 GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock", 842 GNUNET_snprintf (uval,
843 sizeof (uval),
844 "%s/%s.sock",
843 uc->gnunet_home, section); 845 uc->gnunet_home, section);
844 value = uval; 846 value = uval;
845 } 847 }
diff --git a/src/topology/friends.c b/src/topology/friends.c
index 4278e1266..f23724444 100644
--- a/src/topology/friends.c
+++ b/src/topology/friends.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
diff --git a/src/topology/test_gnunet_daemon_topology_data.conf b/src/topology/test_gnunet_daemon_topology_data.conf
index 43d3da375..8d8636bff 100644
--- a/src/topology/test_gnunet_daemon_topology_data.conf
+++ b/src/topology/test_gnunet_daemon_topology_data.conf
@@ -24,3 +24,7 @@ USE_HOSTNAME = NO
24 24
25[nse] 25[nse]
26WORKBITS = 0 26WORKBITS = 0
27
28[rps]
29START_ON_DEMAND = NO
30IMMEDIATE_START = NO
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am
index 3de46cf6f..9cf16ddb6 100644
--- a/src/transport/Makefile.am
+++ b/src/transport/Makefile.am
@@ -154,6 +154,7 @@ endif
154 154
155lib_LTLIBRARIES = \ 155lib_LTLIBRARIES = \
156 libgnunettransport.la \ 156 libgnunettransport.la \
157 libgnunettransportaddress.la \
157 libgnunettransportcore.la \ 158 libgnunettransportcore.la \
158 libgnunettransportcommunicator.la \ 159 libgnunettransportcommunicator.la \
159 libgnunettransportmonitor.la \ 160 libgnunettransportmonitor.la \
@@ -197,6 +198,15 @@ libgnunettransport_la_LDFLAGS = \
197 198
198 199
199 200
201libgnunettransportaddress_la_SOURCES = \
202 transport_api2_address.c
203libgnunettransportaddress_la_LIBADD = \
204 $(top_builddir)/src/util/libgnunetutil.la \
205 $(GN_LIBINTL)
206libgnunettransportaddress_la_LDFLAGS = \
207 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
208 -version-info 0:0:0
209
200libgnunettransportcore_la_SOURCES = \ 210libgnunettransportcore_la_SOURCES = \
201 transport_api2_core.c 211 transport_api2_core.c
202libgnunettransportcore_la_LIBADD = \ 212libgnunettransportcore_la_LIBADD = \
@@ -271,7 +281,7 @@ gnunet_communicator_udp_LDADD = \
271 $(top_builddir)/src/nt/libgnunetnt.la \ 281 $(top_builddir)/src/nt/libgnunetnt.la \
272 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 282 $(top_builddir)/src/statistics/libgnunetstatistics.la \
273 $(top_builddir)/src/util/libgnunetutil.la \ 283 $(top_builddir)/src/util/libgnunetutil.la \
274 $(LIBGCRYPT_LIBS) 284 $(LIBGCRYPT_LIBS)
275 285
276 286
277gnunet_helper_transport_wlan_SOURCES = \ 287gnunet_helper_transport_wlan_SOURCES = \
@@ -1339,6 +1349,7 @@ test_transport_api_slow_ats_LDADD = \
1339 1349
1340 1350
1341EXTRA_DIST = \ 1351EXTRA_DIST = \
1352communicator-unix.conf \
1342test_plugin_hostkey \ 1353test_plugin_hostkey \
1343test_plugin_hostkey.ecc \ 1354test_plugin_hostkey.ecc \
1344test_delay \ 1355test_delay \
diff --git a/src/transport/gnunet-communicator-tcp.c b/src/transport/gnunet-communicator-tcp.c
index 93f510be0..47bffa2ba 100644
--- a/src/transport/gnunet-communicator-tcp.c
+++ b/src/transport/gnunet-communicator-tcp.c
@@ -24,7 +24,7 @@
24 * @author Christian Grothoff 24 * @author Christian Grothoff
25 * 25 *
26 * TODO: 26 * TODO:
27 * - add and use util/ check for IPv6 availability (#V6) 27 * - add and use util/ check for IPv6 availability (#5553)
28 * - support DNS names in BINDTO option (#5528) 28 * - support DNS names in BINDTO option (#5528)
29 * - support NAT connection reversal method (#5529) 29 * - support NAT connection reversal method (#5529)
30 * - support other TCP-specific NAT traversal methods (#5531) 30 * - support other TCP-specific NAT traversal methods (#5531)
diff --git a/src/transport/gnunet-communicator-udp.c b/src/transport/gnunet-communicator-udp.c
index c88f7f6f5..550ba7c85 100644
--- a/src/transport/gnunet-communicator-udp.c
+++ b/src/transport/gnunet-communicator-udp.c
@@ -24,14 +24,14 @@
24 * @author Christian Grothoff 24 * @author Christian Grothoff
25 * 25 *
26 * TODO: 26 * TODO:
27 * - add and use util/ check for IPv6 availability (#V6) 27 * - add and use util/ check for IPv6 availability (#5553)
28 * - consider imposing transmission limits in the absence 28 * - consider imposing transmission limits in the absence
29 * of ACKs; or: maybe this should be done at TNG service level? 29 * of ACKs; or: maybe this should be done at TNG service level?
30 * (at least the receiver might want to enforce limits on 30 * (at least the receiver might want to enforce limits on
31 * KX/DH operations per sender in here) 31 * KX/DH operations per sender in here) (#5552)
32 * - overall, we should look more into flow control support 32 * - overall, we should look more into flow control support
33 * (either in backchannel, or general solution in TNG service) 33 * (either in backchannel, or general solution in TNG service)
34 * - handle addresses discovered from broadcasts (#BC) 34 * - handle addresses discovered from broadcasts (#5551)
35 * (think: what was the story again on address validation? 35 * (think: what was the story again on address validation?
36 * where is the API for that!?!) 36 * where is the API for that!?!)
37 * - support DNS names in BINDTO option (#5528) 37 * - support DNS names in BINDTO option (#5528)
@@ -1672,7 +1672,7 @@ sock_read (void *cls)
1672 "# broadcasts received", 1672 "# broadcasts received",
1673 1, 1673 1,
1674 GNUNET_NO); 1674 GNUNET_NO);
1675 // FIXME #BC: we effectively just got a HELLO! 1675 // FIXME #5551: we effectively just got a HELLO!
1676 // trigger verification NOW! 1676 // trigger verification NOW!
1677 return; 1677 return;
1678 } 1678 }
diff --git a/src/transport/gnunet-service-tng.c b/src/transport/gnunet-service-tng.c
index d392b3a46..7d7d04375 100644
--- a/src/transport/gnunet-service-tng.c
+++ b/src/transport/gnunet-service-tng.c
@@ -46,16 +46,17 @@
46 * #6 to ensure flow control and RTT are OK, we always do the 46 * #6 to ensure flow control and RTT are OK, we always do the
47 * 'validation', even if address comes from PEERSTORE 47 * 'validation', even if address comes from PEERSTORE
48 * #7 48 * #7
49 * - ACK handling / retransmission 49 * - ACK handling / retransmission
50 * - address verification
50 * - track RTT, distance, loss, etc. 51 * - track RTT, distance, loss, etc.
51 * - DV data structures: 52 * - DV data structures:
52 * + learning 53 * + learning
53 * + forgetting 54 * + forgetting
54 * + using them! 55 * + using them!
55 * - routing of messages (using DV data structures!) 56 * - routing of messages (using DV data structures!)
56 * - handling of DV-boxed messages that need to be forwarded 57 * - handling of DV-boxed messages that need to be forwarded
57 * - backchannel message encryption & decryption 58 * - backchannel message encryption & decryption
58 * - 59 * -
59 * 60 *
60 * Easy: 61 * Easy:
61 * - use ATS bandwidth allocation callback and schedule transmissions! 62 * - use ATS bandwidth allocation callback and schedule transmissions!
@@ -72,7 +73,7 @@
72 * (requires planning at receiver, and additional MST-style demultiplex 73 * (requires planning at receiver, and additional MST-style demultiplex
73 * at receiver!) 74 * at receiver!)
74 * - could avoid copying body of message into each fragment and keep 75 * - could avoid copying body of message into each fragment and keep
75 * fragments as just pointers into the original message and only 76 * fragments as just pointers into the original message and only
76 * fully build fragments just before transmission (optimization, should 77 * fully build fragments just before transmission (optimization, should
77 * reduce CPU and memory use) 78 * reduce CPU and memory use)
78 * 79 *
@@ -141,7 +142,7 @@
141/** 142/**
142 * How many messages can we have pending for a given communicator 143 * How many messages can we have pending for a given communicator
143 * process before we start to throttle that communicator? 144 * process before we start to throttle that communicator?
144 * 145 *
145 * Used if a communicator might be CPU-bound and cannot handle the traffic. 146 * Used if a communicator might be CPU-bound and cannot handle the traffic.
146 */ 147 */
147#define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512 148#define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
@@ -150,7 +151,7 @@
150 * How many messages can we have pending for a given session (queue to 151 * How many messages can we have pending for a given session (queue to
151 * a particular peer via a communicator) process before we start to 152 * a particular peer via a communicator) process before we start to
152 * throttle that queue? 153 * throttle that queue?
153 * 154 *
154 * Used if ATS assigns more bandwidth to a particular transmission 155 * Used if ATS assigns more bandwidth to a particular transmission
155 * method than that transmission method can right now handle. (Yes, 156 * method than that transmission method can right now handle. (Yes,
156 * ATS should eventually notice utilization below allocation and 157 * ATS should eventually notice utilization below allocation and
@@ -195,7 +196,7 @@ struct TransportBackchannelEncapsulationMessage
195 196
196 // FIXME: probably should add random IV here as well, 197 // FIXME: probably should add random IV here as well,
197 // especially if we re-use ephemeral keys! 198 // especially if we re-use ephemeral keys!
198 199
199 /** 200 /**
200 * HMAC over the ciphertext of the encrypted, variable-size 201 * HMAC over the ciphertext of the encrypted, variable-size
201 * body that follows. Verified via DH of @e target and 202 * body that follows. Verified via DH of @e target and
@@ -224,8 +225,8 @@ struct EphemeralConfirmation
224 * only interpret the value as a mononic time and reject 225 * only interpret the value as a mononic time and reject
225 * "older" values than the last one observed. Even with this, 226 * "older" values than the last one observed. Even with this,
226 * there is no real guarantee against replay achieved here, 227 * there is no real guarantee against replay achieved here,
227 * as the latest timestamp is not persisted. This is 228 * as the latest timestamp is not persisted. This is
228 * necessary as we do not want to require synchronized 229 * necessary as we do not want to require synchronized
229 * clocks and may not have a bidirectional communication 230 * clocks and may not have a bidirectional communication
230 * channel. Communicators must protect against replay 231 * channel. Communicators must protect against replay
231 * attacks when using backchannel communication! 232 * attacks when using backchannel communication!
@@ -373,17 +374,17 @@ struct TransportFragmentBox
373 /** 374 /**
374 * Original message ID for of the message that all the1 375 * Original message ID for of the message that all the1
375 * fragments belong to. Must be the same for all fragments. 376 * fragments belong to. Must be the same for all fragments.
376 */ 377 */
377 struct GNUNET_ShortHashCode msg_uuid; 378 struct GNUNET_ShortHashCode msg_uuid;
378 379
379 /** 380 /**
380 * Offset of this fragment in the overall message. 381 * Offset of this fragment in the overall message.
381 */ 382 */
382 uint16_t frag_off GNUNET_PACKED; 383 uint16_t frag_off GNUNET_PACKED;
383 384
384 /** 385 /**
385 * Total size of the message that is being fragmented. 386 * Total size of the message that is being fragmented.
386 */ 387 */
387 uint16_t msg_size GNUNET_PACKED; 388 uint16_t msg_size GNUNET_PACKED;
388 389
389}; 390};
@@ -412,13 +413,13 @@ struct TransportFragmentAckMessage
412 /** 413 /**
413 * Bitfield of up to 64 additional fragments following the 414 * Bitfield of up to 64 additional fragments following the
414 * @e msg_uuid being acknowledged by this message. 415 * @e msg_uuid being acknowledged by this message.
415 */ 416 */
416 uint64_t extra_acks GNUNET_PACKED; 417 uint64_t extra_acks GNUNET_PACKED;
417 418
418 /** 419 /**
419 * Original message ID for of the message that all the 420 * Original message ID for of the message that all the
420 * fragments belong to. 421 * fragments belong to.
421 */ 422 */
422 struct GNUNET_ShortHashCode msg_uuid; 423 struct GNUNET_ShortHashCode msg_uuid;
423 424
424 /** 425 /**
@@ -444,7 +445,7 @@ struct TransportFragmentAckMessage
444 * to a subset of their neighbours to limit discoverability of the 445 * to a subset of their neighbours to limit discoverability of the
445 * network topology). To the extend that the @e bidirectional bits 446 * network topology). To the extend that the @e bidirectional bits
446 * are set, peers may learn the inverse paths even if they did not 447 * are set, peers may learn the inverse paths even if they did not
447 * initiate. 448 * initiate.
448 * 449 *
449 * Unless received on a bidirectional queue and @e num_hops just 450 * Unless received on a bidirectional queue and @e num_hops just
450 * zero, peers that can forward to the initator should always try to 451 * zero, peers that can forward to the initator should always try to
@@ -469,13 +470,13 @@ struct TransportDVLearn
469 * to possibly instantly learn a path in both directions. Each peer 470 * to possibly instantly learn a path in both directions. Each peer
470 * should shift this value by one to the left, and then set the 471 * should shift this value by one to the left, and then set the
471 * lowest bit IF the current sender can be reached from it (without 472 * lowest bit IF the current sender can be reached from it (without
472 * DV routing). 473 * DV routing).
473 */ 474 */
474 uint16_t bidirectional GNUNET_PACKED; 475 uint16_t bidirectional GNUNET_PACKED;
475 476
476 /** 477 /**
477 * Peers receiving this message and delaying forwarding to other 478 * Peers receiving this message and delaying forwarding to other
478 * peers for any reason should increment this value such as to 479 * peers for any reason should increment this value such as to
479 * enable the origin to determine the actual network-only delay 480 * enable the origin to determine the actual network-only delay
480 * in addition to the real-time delay (assuming the message loops 481 * in addition to the real-time delay (assuming the message loops
481 * back to the origin). 482 * back to the origin).
@@ -486,11 +487,11 @@ struct TransportDVLearn
486 * Identity of the peer that started this learning activity. 487 * Identity of the peer that started this learning activity.
487 */ 488 */
488 struct GNUNET_PeerIdentity initiator; 489 struct GNUNET_PeerIdentity initiator;
489 490
490 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values, 491 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values,
491 excluding the initiator of the DV trace; the last entry is the 492 excluding the initiator of the DV trace; the last entry is the
492 current sender; the current peer must not be included. */ 493 current sender; the current peer must not be included. */
493 494
494}; 495};
495 496
496 497
@@ -527,7 +528,7 @@ struct TransportDVBox
527 * Number of hops this messages includes. In NBO. 528 * Number of hops this messages includes. In NBO.
528 */ 529 */
529 uint16_t num_hops GNUNET_PACKED; 530 uint16_t num_hops GNUNET_PACKED;
530 531
531 /** 532 /**
532 * Identity of the peer that originated the message. 533 * Identity of the peer that originated the message.
533 */ 534 */
@@ -577,7 +578,7 @@ enum ClientType
577/** 578/**
578 * Entry in our cache of ephemeral keys we currently use. 579 * Entry in our cache of ephemeral keys we currently use.
579 * This way, we only sign an ephemeral once per @e target, 580 * This way, we only sign an ephemeral once per @e target,
580 * and then can re-use it over multiple 581 * and then can re-use it over multiple
581 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION 582 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION
582 * messages (as signing is expensive). 583 * messages (as signing is expensive).
583 */ 584 */
@@ -645,39 +646,39 @@ struct DistanceVectorHop
645 646
646 /** 647 /**
647 * Kept in a MDLL, sorted by @e timeout. 648 * Kept in a MDLL, sorted by @e timeout.
648 */ 649 */
649 struct DistanceVectorHop *next_dv; 650 struct DistanceVectorHop *next_dv;
650 651
651 /** 652 /**
652 * Kept in a MDLL, sorted by @e timeout. 653 * Kept in a MDLL, sorted by @e timeout.
653 */ 654 */
654 struct DistanceVectorHop *prev_dv; 655 struct DistanceVectorHop *prev_dv;
655 656
656 /** 657 /**
657 * Kept in a MDLL. 658 * Kept in a MDLL.
658 */ 659 */
659 struct DistanceVectorHop *next_neighbour; 660 struct DistanceVectorHop *next_neighbour;
660 661
661 /** 662 /**
662 * Kept in a MDLL. 663 * Kept in a MDLL.
663 */ 664 */
664 struct DistanceVectorHop *prev_neighbour; 665 struct DistanceVectorHop *prev_neighbour;
665 666
666 /** 667 /**
667 * What would be the next hop to @e target? 668 * What would be the next hop to @e target?
668 */ 669 */
669 struct Neighbour *next_hop; 670 struct Neighbour *next_hop;
670 671
671 /** 672 /**
672 * Distance vector entry this hop belongs with. 673 * Distance vector entry this hop belongs with.
673 */ 674 */
674 struct DistanceVector *dv; 675 struct DistanceVector *dv;
675 676
676 /** 677 /**
677 * Array of @e distance hops to the target, excluding @e next_hop. 678 * Array of @e distance hops to the target, excluding @e next_hop.
678 * NULL if the entire path is us to @e next_hop to `target`. Allocated 679 * NULL if the entire path is us to @e next_hop to `target`. Allocated
679 * at the end of this struct. 680 * at the end of this struct.
680 */ 681 */
681 const struct GNUNET_PeerIdentity *path; 682 const struct GNUNET_PeerIdentity *path;
682 683
683 /** 684 /**
@@ -685,11 +686,11 @@ struct DistanceVectorHop
685 * while learning? 686 * while learning?
686 */ 687 */
687 struct GNUNET_TIME_Absolute timeout; 688 struct GNUNET_TIME_Absolute timeout;
688 689
689 /** 690 /**
690 * How many hops in total to the `target` (excluding @e next_hop and `target` itself), 691 * How many hops in total to the `target` (excluding @e next_hop and `target` itself),
691 * thus 0 still means a distance of 2 hops (to @e next_hop and then to `target`)? 692 * thus 0 still means a distance of 2 hops (to @e next_hop and then to `target`)?
692 */ 693 */
693 unsigned int distance; 694 unsigned int distance;
694}; 695};
695 696
@@ -708,12 +709,12 @@ struct DistanceVector
708 709
709 /** 710 /**
710 * Known paths to @e target. 711 * Known paths to @e target.
711 */ 712 */
712 struct DistanceVectorHop *dv_head; 713 struct DistanceVectorHop *dv_head;
713 714
714 /** 715 /**
715 * Known paths to @e target. 716 * Known paths to @e target.
716 */ 717 */
717 struct DistanceVectorHop *dv_tail; 718 struct DistanceVectorHop *dv_tail;
718 719
719 /** 720 /**
@@ -737,19 +738,19 @@ struct QueueEntry
737 738
738 /** 739 /**
739 * Kept as a DLL. 740 * Kept as a DLL.
740 */ 741 */
741 struct QueueEntry *next; 742 struct QueueEntry *next;
742 743
743 /** 744 /**
744 * Kept as a DLL. 745 * Kept as a DLL.
745 */ 746 */
746 struct QueueEntry *prev; 747 struct QueueEntry *prev;
747 748
748 /** 749 /**
749 * ATS session this entry is queued with. 750 * ATS session this entry is queued with.
750 */ 751 */
751 struct GNUNET_ATS_Session *session; 752 struct GNUNET_ATS_Session *session;
752 753
753 /** 754 /**
754 * Message ID used for this message with the queue used for transmission. 755 * Message ID used for this message with the queue used for transmission.
755 */ 756 */
@@ -785,12 +786,12 @@ struct GNUNET_ATS_Session
785 786
786 /** 787 /**
787 * Head of DLL of unacked transmission requests. 788 * Head of DLL of unacked transmission requests.
788 */ 789 */
789 struct QueueEntry *queue_head; 790 struct QueueEntry *queue_head;
790 791
791 /** 792 /**
792 * End of DLL of unacked transmission requests. 793 * End of DLL of unacked transmission requests.
793 */ 794 */
794 struct QueueEntry *queue_tail; 795 struct QueueEntry *queue_tail;
795 796
796 /** 797 /**
@@ -816,9 +817,9 @@ struct GNUNET_ATS_Session
816 /** 817 /**
817 * Task scheduled for the time when this queue can (likely) transmit the 818 * Task scheduled for the time when this queue can (likely) transmit the
818 * next message. Still needs to check with the @e tracker_out to be sure. 819 * next message. Still needs to check with the @e tracker_out to be sure.
819 */ 820 */
820 struct GNUNET_SCHEDULER_Task *transmit_task; 821 struct GNUNET_SCHEDULER_Task *transmit_task;
821 822
822 /** 823 /**
823 * Our current RTT estimate for this ATS session. 824 * Our current RTT estimate for this ATS session.
824 */ 825 */
@@ -826,9 +827,9 @@ struct GNUNET_ATS_Session
826 827
827 /** 828 /**
828 * Message ID generator for transmissions on this queue. 829 * Message ID generator for transmissions on this queue.
829 */ 830 */
830 uint64_t mid_gen; 831 uint64_t mid_gen;
831 832
832 /** 833 /**
833 * Unique identifier of this ATS session with the communicator. 834 * Unique identifier of this ATS session with the communicator.
834 */ 835 */
@@ -858,7 +859,7 @@ struct GNUNET_ATS_Session
858 * Length of the DLL starting at @e queue_head. 859 * Length of the DLL starting at @e queue_head.
859 */ 860 */
860 unsigned int queue_length; 861 unsigned int queue_length;
861 862
862 /** 863 /**
863 * Network type offered by this ATS session. 864 * Network type offered by this ATS session.
864 */ 865 */
@@ -883,14 +884,14 @@ struct GNUNET_ATS_Session
883 884
884/** 885/**
885 * Information we keep for a message that we are reassembling. 886 * Information we keep for a message that we are reassembling.
886 */ 887 */
887struct ReassemblyContext 888struct ReassemblyContext
888{ 889{
889 890
890 /** 891 /**
891 * Original message ID for of the message that all the 892 * Original message ID for of the message that all the
892 * fragments belong to. 893 * fragments belong to.
893 */ 894 */
894 struct GNUNET_ShortHashCode msg_uuid; 895 struct GNUNET_ShortHashCode msg_uuid;
895 896
896 /** 897 /**
@@ -900,7 +901,7 @@ struct ReassemblyContext
900 901
901 /** 902 /**
902 * Entry in the reassembly heap (sorted by expiration). 903 * Entry in the reassembly heap (sorted by expiration).
903 */ 904 */
904 struct GNUNET_CONTAINER_HeapNode *hn; 905 struct GNUNET_CONTAINER_HeapNode *hn;
905 906
906 /** 907 /**
@@ -918,7 +919,7 @@ struct ReassemblyContext
918 * task is for the latter case. 919 * task is for the latter case.
919 */ 920 */
920 struct GNUNET_SCHEDULER_Task *ack_task; 921 struct GNUNET_SCHEDULER_Task *ack_task;
921 922
922 /** 923 /**
923 * At what time will we give up reassembly of this message? 924 * At what time will we give up reassembly of this message?
924 */ 925 */
@@ -941,7 +942,7 @@ struct ReassemblyContext
941 * to be acknowledged in the next cummulative ACK. 942 * to be acknowledged in the next cummulative ACK.
942 */ 943 */
943 uint64_t extra_acks; 944 uint64_t extra_acks;
944 945
945 /** 946 /**
946 * Unique ID of the lowest fragment UUID to be acknowledged in the 947 * Unique ID of the lowest fragment UUID to be acknowledged in the
947 * next cummulative ACK. Only valid if @e num_acks > 0. 948 * next cummulative ACK. Only valid if @e num_acks > 0.
@@ -953,7 +954,7 @@ struct ReassemblyContext
953 * whenever we send a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK. 954 * whenever we send a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK.
954 */ 955 */
955 unsigned int num_acks; 956 unsigned int num_acks;
956 957
957 /** 958 /**
958 * How big is the message we are reassembling in total? 959 * How big is the message we are reassembling in total?
959 */ 960 */
@@ -986,21 +987,21 @@ struct Neighbour
986 * Map with `struct ReassemblyContext` structs for fragments under 987 * Map with `struct ReassemblyContext` structs for fragments under
987 * reassembly. May be NULL if we currently have no fragments from 988 * reassembly. May be NULL if we currently have no fragments from
988 * this @e pid (lazy initialization). 989 * this @e pid (lazy initialization).
989 */ 990 */
990 struct GNUNET_CONTAINER_MultiShortmap *reassembly_map; 991 struct GNUNET_CONTAINER_MultiShortmap *reassembly_map;
991 992
992 /** 993 /**
993 * Heap with `struct ReassemblyContext` structs for fragments under 994 * Heap with `struct ReassemblyContext` structs for fragments under
994 * reassembly. May be NULL if we currently have no fragments from 995 * reassembly. May be NULL if we currently have no fragments from
995 * this @e pid (lazy initialization). 996 * this @e pid (lazy initialization).
996 */ 997 */
997 struct GNUNET_CONTAINER_Heap *reassembly_heap; 998 struct GNUNET_CONTAINER_Heap *reassembly_heap;
998 999
999 /** 1000 /**
1000 * Task to free old entries from the @e reassembly_heap and @e reassembly_map. 1001 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1001 */ 1002 */
1002 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task; 1003 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1003 1004
1004 /** 1005 /**
1005 * Head of list of messages pending for this neighbour. 1006 * Head of list of messages pending for this neighbour.
1006 */ 1007 */
@@ -1014,13 +1015,13 @@ struct Neighbour
1014 /** 1015 /**
1015 * Head of MDLL of DV hops that have this neighbour as next hop. Must be 1016 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1016 * purged if this neighbour goes down. 1017 * purged if this neighbour goes down.
1017 */ 1018 */
1018 struct DistanceVectorHop *dv_head; 1019 struct DistanceVectorHop *dv_head;
1019 1020
1020 /** 1021 /**
1021 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be 1022 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1022 * purged if this neighbour goes down. 1023 * purged if this neighbour goes down.
1023 */ 1024 */
1024 struct DistanceVectorHop *dv_tail; 1025 struct DistanceVectorHop *dv_tail;
1025 1026
1026 /** 1027 /**
@@ -1035,7 +1036,7 @@ struct Neighbour
1035 1036
1036 /** 1037 /**
1037 * Task run to cleanup pending messages that have exceeded their timeout. 1038 * Task run to cleanup pending messages that have exceeded their timeout.
1038 */ 1039 */
1039 struct GNUNET_SCHEDULER_Task *timeout_task; 1040 struct GNUNET_SCHEDULER_Task *timeout_task;
1040 1041
1041 /** 1042 /**
@@ -1052,15 +1053,15 @@ struct Neighbour
1052 1053
1053 /** 1054 /**
1054 * What is the earliest timeout of any message in @e pending_msg_tail? 1055 * What is the earliest timeout of any message in @e pending_msg_tail?
1055 */ 1056 */
1056 struct GNUNET_TIME_Absolute earliest_timeout; 1057 struct GNUNET_TIME_Absolute earliest_timeout;
1057 1058
1058}; 1059};
1059 1060
1060 1061
1061/** 1062/**
1062 * Types of different pending messages. 1063 * Types of different pending messages.
1063 */ 1064 */
1064enum PendingMessageType 1065enum PendingMessageType
1065{ 1066{
1066 1067
@@ -1084,7 +1085,7 @@ enum PendingMessageType
1084 */ 1085 */
1085 PMT_ACKNOWLEDGEMENT = 3 1086 PMT_ACKNOWLEDGEMENT = 3
1086 1087
1087 1088
1088}; 1089};
1089 1090
1090 1091
@@ -1101,13 +1102,13 @@ enum PendingMessageType
1101 * either calculate the next fragment (based on @e frag_off) from the 1102 * either calculate the next fragment (based on @e frag_off) from the
1102 * current node, or, if all fragments have already been created, 1103 * current node, or, if all fragments have already been created,
1103 * descend to the @e head_frag. Even though the node was already 1104 * descend to the @e head_frag. Even though the node was already
1104 * fragmented, the fragment may be too big if the fragment was 1105 * fragmented, the fragment may be too big if the fragment was
1105 * generated for a queue with a larger MTU. In this case, the node 1106 * generated for a queue with a larger MTU. In this case, the node
1106 * may be fragmented again, thus creating a tree. 1107 * may be fragmented again, thus creating a tree.
1107 * 1108 *
1108 * When acknowledgements for fragments are received, the tree 1109 * When acknowledgements for fragments are received, the tree
1109 * must be pruned, removing those parts that were already 1110 * must be pruned, removing those parts that were already
1110 * acknowledged. When fragments are sent over a reliable 1111 * acknowledged. When fragments are sent over a reliable
1111 * channel, they can be immediately removed. 1112 * channel, they can be immediately removed.
1112 * 1113 *
1113 * If a message is ever fragmented, then the original "full" message 1114 * If a message is ever fragmented, then the original "full" message
@@ -1130,7 +1131,7 @@ struct PendingMessage
1130 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE) 1131 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1131 */ 1132 */
1132 struct PendingMessage *next_client; 1133 struct PendingMessage *next_client;
1133 1134
1134 /** 1135 /**
1135 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE) 1136 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
1136 */ 1137 */
@@ -1140,7 +1141,7 @@ struct PendingMessage
1140 * Kept in a MDLL of messages from this @a cpm (if @e pmt is #PMT_FRAGMENT_BOx) 1141 * Kept in a MDLL of messages from this @a cpm (if @e pmt is #PMT_FRAGMENT_BOx)
1141 */ 1142 */
1142 struct PendingMessage *next_frag; 1143 struct PendingMessage *next_frag;
1143 1144
1144 /** 1145 /**
1145 * Kept in a MDLL of messages from this @a cpm (if @e pmt is #PMT_FRAGMENT_BOX) 1146 * Kept in a MDLL of messages from this @a cpm (if @e pmt is #PMT_FRAGMENT_BOX)
1146 */ 1147 */
@@ -1148,24 +1149,24 @@ struct PendingMessage
1148 1149
1149 /** 1150 /**
1150 * This message, reliability boxed. Only possibly available if @e pmt is #PMT_CORE. 1151 * This message, reliability boxed. Only possibly available if @e pmt is #PMT_CORE.
1151 */ 1152 */
1152 struct PendingMessage *bpm; 1153 struct PendingMessage *bpm;
1153 1154
1154 /** 1155 /**
1155 * Target of the request. 1156 * Target of the request.
1156 */ 1157 */
1157 struct Neighbour *target; 1158 struct Neighbour *target;
1158 1159
1159 /** 1160 /**
1160 * Client that issued the transmission request, if @e pmt is #PMT_CORE. 1161 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
1161 */ 1162 */
1162 struct TransportClient *client; 1163 struct TransportClient *client;
1163 1164
1164 /** 1165 /**
1165 * Head of a MDLL of fragments created for this core message. 1166 * Head of a MDLL of fragments created for this core message.
1166 */ 1167 */
1167 struct PendingMessage *head_frag; 1168 struct PendingMessage *head_frag;
1168 1169
1169 /** 1170 /**
1170 * Tail of a MDLL of fragments created for this core message. 1171 * Tail of a MDLL of fragments created for this core message.
1171 */ 1172 */
@@ -1175,7 +1176,7 @@ struct PendingMessage
1175 * Our parent in the fragmentation tree. 1176 * Our parent in the fragmentation tree.
1176 */ 1177 */
1177 struct PendingMessage *frag_parent; 1178 struct PendingMessage *frag_parent;
1178 1179
1179 /** 1180 /**
1180 * At what time should we give up on the transmission (and no longer retry)? 1181 * At what time should we give up on the transmission (and no longer retry)?
1181 */ 1182 */
@@ -1191,12 +1192,12 @@ struct PendingMessage
1191 * initialized if @e msg_uuid_set is #GNUNET_YES). 1192 * initialized if @e msg_uuid_set is #GNUNET_YES).
1192 */ 1193 */
1193 struct GNUNET_ShortHashCode msg_uuid; 1194 struct GNUNET_ShortHashCode msg_uuid;
1194 1195
1195 /** 1196 /**
1196 * Counter incremented per generated fragment. 1197 * Counter incremented per generated fragment.
1197 */ 1198 */
1198 uint32_t frag_uuidgen; 1199 uint32_t frag_uuidgen;
1199 1200
1200 /** 1201 /**
1201 * Type of the pending message. 1202 * Type of the pending message.
1202 */ 1203 */
@@ -1209,14 +1210,14 @@ struct PendingMessage
1209 1210
1210 /** 1211 /**
1211 * Offset at which we should generate the next fragment. 1212 * Offset at which we should generate the next fragment.
1212 */ 1213 */
1213 uint16_t frag_off; 1214 uint16_t frag_off;
1214 1215
1215 /** 1216 /**
1216 * #GNUNET_YES once @e msg_uuid was initialized 1217 * #GNUNET_YES once @e msg_uuid was initialized
1217 */ 1218 */
1218 int16_t msg_uuid_set; 1219 int16_t msg_uuid_set;
1219 1220
1220 /* Followed by @e bytes_msg to transmit */ 1221 /* Followed by @e bytes_msg to transmit */
1221}; 1222};
1222 1223
@@ -1316,7 +1317,7 @@ struct TransportClient
1316 struct { 1317 struct {
1317 1318
1318 /** 1319 /**
1319 * Head of list of messages pending for this client, sorted by 1320 * Head of list of messages pending for this client, sorted by
1320 * transmission time ("next_attempt" + possibly internal prioritization). 1321 * transmission time ("next_attempt" + possibly internal prioritization).
1321 */ 1322 */
1322 struct PendingMessage *pending_msg_head; 1323 struct PendingMessage *pending_msg_head;
@@ -1384,7 +1385,7 @@ struct TransportClient
1384 * is globally unable to keep up. 1385 * is globally unable to keep up.
1385 */ 1386 */
1386 unsigned int total_queue_length; 1387 unsigned int total_queue_length;
1387 1388
1388 /** 1389 /**
1389 * Characteristics of this communicator. 1390 * Characteristics of this communicator.
1390 */ 1391 */
@@ -1559,7 +1560,7 @@ free_distance_vector_hop (struct DistanceVectorHop *dvh)
1559 GNUNET_free (dvh); 1560 GNUNET_free (dvh);
1560 if (NULL == dv->dv_head) 1561 if (NULL == dv->dv_head)
1561 { 1562 {
1562 GNUNET_assert (GNUNET_YES == 1563 GNUNET_assert (GNUNET_YES ==
1563 GNUNET_CONTAINER_multipeermap_remove (dv_routes, 1564 GNUNET_CONTAINER_multipeermap_remove (dv_routes,
1564 &dv->target, 1565 &dv->target,
1565 dv)); 1566 dv));
@@ -1764,7 +1765,7 @@ free_reassembly_cb (void *cls,
1764 struct ReassemblyContext *rc = value; 1765 struct ReassemblyContext *rc = value;
1765 (void) cls; 1766 (void) cls;
1766 (void) key; 1767 (void) key;
1767 1768
1768 free_reassembly_context (rc); 1769 free_reassembly_context (rc);
1769 return GNUNET_OK; 1770 return GNUNET_OK;
1770} 1771}
@@ -1779,7 +1780,7 @@ static void
1779free_neighbour (struct Neighbour *neighbour) 1780free_neighbour (struct Neighbour *neighbour)
1780{ 1781{
1781 struct DistanceVectorHop *dvh; 1782 struct DistanceVectorHop *dvh;
1782 1783
1783 GNUNET_assert (NULL == neighbour->session_head); 1784 GNUNET_assert (NULL == neighbour->session_head);
1784 GNUNET_assert (GNUNET_YES == 1785 GNUNET_assert (GNUNET_YES ==
1785 GNUNET_CONTAINER_multipeermap_remove (neighbours, 1786 GNUNET_CONTAINER_multipeermap_remove (neighbours,
@@ -1881,25 +1882,25 @@ cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
1881 1882
1882/** 1883/**
1883 * We believe we are ready to transmit a message on a queue. Double-checks 1884 * We believe we are ready to transmit a message on a queue. Double-checks
1884 * with the queue's "tracker_out" and then gives the message to the 1885 * with the queue's "tracker_out" and then gives the message to the
1885 * communicator for transmission (updating the tracker, and re-scheduling 1886 * communicator for transmission (updating the tracker, and re-scheduling
1886 * itself if applicable). 1887 * itself if applicable).
1887 * 1888 *
1888 * @param cls the `struct GNUNET_ATS_Session` to process transmissions for 1889 * @param cls the `struct GNUNET_ATS_Session` to process transmissions for
1889 */ 1890 */
1890static void 1891static void
1891transmit_on_queue (void *cls); 1892transmit_on_queue (void *cls);
1892 1893
1893 1894
1894/** 1895/**
1895 * Schedule next run of #transmit_on_queue(). Does NOTHING if 1896 * Schedule next run of #transmit_on_queue(). Does NOTHING if
1896 * we should run immediately or if the message queue is empty. 1897 * we should run immediately or if the message queue is empty.
1897 * Test for no task being added AND queue not being empty to 1898 * Test for no task being added AND queue not being empty to
1898 * transmit immediately afterwards! This function must only 1899 * transmit immediately afterwards! This function must only
1899 * be called if the message queue is non-empty! 1900 * be called if the message queue is non-empty!
1900 * 1901 *
1901 * @param queue the queue to do scheduling for 1902 * @param queue the queue to do scheduling for
1902 */ 1903 */
1903static void 1904static void
1904schedule_transmit_on_queue (struct GNUNET_ATS_Session *queue) 1905schedule_transmit_on_queue (struct GNUNET_ATS_Session *queue)
1905{ 1906{
@@ -1914,7 +1915,7 @@ schedule_transmit_on_queue (struct GNUNET_ATS_Session *queue)
1914 GNUNET_STATISTICS_update (GST_stats, 1915 GNUNET_STATISTICS_update (GST_stats,
1915 "# Transmission throttled due to communicator queue limit", 1916 "# Transmission throttled due to communicator queue limit",
1916 1, 1917 1,
1917 GNUNET_NO); 1918 GNUNET_NO);
1918 return; 1919 return;
1919 } 1920 }
1920 if (queue->queue_length >= SESSION_QUEUE_LIMIT) 1921 if (queue->queue_length >= SESSION_QUEUE_LIMIT)
@@ -1922,10 +1923,10 @@ schedule_transmit_on_queue (struct GNUNET_ATS_Session *queue)
1922 GNUNET_STATISTICS_update (GST_stats, 1923 GNUNET_STATISTICS_update (GST_stats,
1923 "# Transmission throttled due to session queue limit", 1924 "# Transmission throttled due to session queue limit",
1924 1, 1925 1,
1925 GNUNET_NO); 1926 GNUNET_NO);
1926 return; 1927 return;
1927 } 1928 }
1928 1929
1929 wsize = (0 == queue->mtu) 1930 wsize = (0 == queue->mtu)
1930 ? pm->bytes_msg /* FIXME: add overheads? */ 1931 ? pm->bytes_msg /* FIXME: add overheads? */
1931 : queue->mtu; 1932 : queue->mtu;
@@ -2213,7 +2214,7 @@ check_client_send (void *cls,
2213 * Free fragment tree below @e root, excluding @e root itself. 2214 * Free fragment tree below @e root, excluding @e root itself.
2214 * 2215 *
2215 * @param root root of the tree to free 2216 * @param root root of the tree to free
2216 */ 2217 */
2217static void 2218static void
2218free_fragment_tree (struct PendingMessage *root) 2219free_fragment_tree (struct PendingMessage *root)
2219{ 2220{
@@ -2328,7 +2329,7 @@ check_queue_timeouts (void *cls)
2328 GNUNET_NO); 2329 GNUNET_NO);
2329 client_send_response (pm, 2330 client_send_response (pm,
2330 GNUNET_NO, 2331 GNUNET_NO,
2331 0); 2332 0);
2332 continue; 2333 continue;
2333 } 2334 }
2334 earliest_timeout = GNUNET_TIME_absolute_min (earliest_timeout, 2335 earliest_timeout = GNUNET_TIME_absolute_min (earliest_timeout,
@@ -2407,7 +2408,7 @@ handle_client_send (void *cls,
2407 target->earliest_timeout.abs_value_us = pm->timeout.abs_value_us; 2408 target->earliest_timeout.abs_value_us = pm->timeout.abs_value_us;
2408 if (NULL != target->timeout_task) 2409 if (NULL != target->timeout_task)
2409 GNUNET_SCHEDULER_cancel (target->timeout_task); 2410 GNUNET_SCHEDULER_cancel (target->timeout_task);
2410 target->timeout_task 2411 target->timeout_task
2411 = GNUNET_SCHEDULER_add_at (target->earliest_timeout, 2412 = GNUNET_SCHEDULER_add_at (target->earliest_timeout,
2412 &check_queue_timeouts, 2413 &check_queue_timeouts,
2413 target); 2414 target);
@@ -2542,7 +2543,7 @@ expire_ephemerals (void *cls)
2542 * one, cache it and return it. 2543 * one, cache it and return it.
2543 * 2544 *
2544 * @param pid peer to look up ephemeral for 2545 * @param pid peer to look up ephemeral for
2545 * @param private_key[out] set to the private key 2546 * @param private_key[out] set to the private key
2546 * @param ephemeral_key[out] set to the key 2547 * @param ephemeral_key[out] set to the key
2547 * @param ephemeral_sender_sig[out] set to the signature 2548 * @param ephemeral_sender_sig[out] set to the signature
2548 * @param ephemeral_validity[out] set to the validity expiration time 2549 * @param ephemeral_validity[out] set to the validity expiration time
@@ -2556,7 +2557,7 @@ lookup_ephemeral (const struct GNUNET_PeerIdentity *pid,
2556{ 2557{
2557 struct EphemeralCacheEntry *ece; 2558 struct EphemeralCacheEntry *ece;
2558 struct EphemeralConfirmation ec; 2559 struct EphemeralConfirmation ec;
2559 2560
2560 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map, 2561 ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map,
2561 pid); 2562 pid);
2562 if ( (NULL != ece) && 2563 if ( (NULL != ece) &&
@@ -2618,7 +2619,7 @@ route_message (const struct GNUNET_PeerIdentity *target,
2618 GNUNET_free (hdr); 2619 GNUNET_free (hdr);
2619} 2620}
2620 2621
2621 2622
2622/** 2623/**
2623 * Communicator requests backchannel transmission. Process the request. 2624 * Communicator requests backchannel transmission. Process the request.
2624 * 2625 *
@@ -2636,7 +2637,7 @@ handle_communicator_backchannel (void *cls,
2636 struct TransportBackchannelRequestPayload ppay; 2637 struct TransportBackchannelRequestPayload ppay;
2637 char *mpos; 2638 char *mpos;
2638 uint16_t msize; 2639 uint16_t msize;
2639 2640
2640 /* encapsulate and encrypt message */ 2641 /* encapsulate and encrypt message */
2641 msize = ntohs (cb->header.size) - sizeof (*cb) + sizeof (struct TransportBackchannelRequestPayload); 2642 msize = ntohs (cb->header.size) - sizeof (*cb) + sizeof (struct TransportBackchannelRequestPayload);
2642 enc = GNUNET_malloc (sizeof (*enc) + msize); 2643 enc = GNUNET_malloc (sizeof (*enc) + msize);
@@ -2871,7 +2872,7 @@ struct CommunicatorMessageContext
2871 * 2872 *
2872 * @param cmc context for demultiplexing 2873 * @param cmc context for demultiplexing
2873 * @param msg message to demultiplex 2874 * @param msg message to demultiplex
2874 */ 2875 */
2875static void 2876static void
2876demultiplex_with_cmc (struct CommunicatorMessageContext *cmc, 2877demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
2877 const struct GNUNET_MessageHeader *msg); 2878 const struct GNUNET_MessageHeader *msg);
@@ -2949,7 +2950,7 @@ handle_raw_message (void *cls,
2949 env); 2950 env);
2950 } 2951 }
2951 /* FIXME: consider doing this _only_ once the message 2952 /* FIXME: consider doing this _only_ once the message
2952 was drained from the CORE MQs to extend flow control to CORE! 2953 was drained from the CORE MQs to extend flow control to CORE!
2953 (basically, increment counter in cmc, decrement on MQ send continuation! */ 2954 (basically, increment counter in cmc, decrement on MQ send continuation! */
2954 finish_cmc_handling (cmc); 2955 finish_cmc_handling (cmc);
2955} 2956}
@@ -2974,12 +2975,12 @@ check_fragment_box (void *cls,
2974 GNUNET_break_op (0); 2975 GNUNET_break_op (0);
2975 return GNUNET_SYSERR; 2976 return GNUNET_SYSERR;
2976 } 2977 }
2977 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size)) 2978 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
2978 { 2979 {
2979 GNUNET_break_op (0); 2980 GNUNET_break_op (0);
2980 return GNUNET_SYSERR; 2981 return GNUNET_SYSERR;
2981 } 2982 }
2982 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size)) 2983 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
2983 { 2984 {
2984 GNUNET_break_op (0); 2985 GNUNET_break_op (0);
2985 return GNUNET_SYSERR; 2986 return GNUNET_SYSERR;
@@ -3046,7 +3047,7 @@ handle_fragment_box (void *cls,
3046 if (NULL == n) 3047 if (NULL == n)
3047 { 3048 {
3048 struct GNUNET_SERVICE_Client *client = cmc->tc->client; 3049 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
3049 3050
3050 GNUNET_break (0); 3051 GNUNET_break (0);
3051 finish_cmc_handling (cmc); 3052 finish_cmc_handling (cmc);
3052 GNUNET_SERVICE_client_drop (client); 3053 GNUNET_SERVICE_client_drop (client);
@@ -3096,7 +3097,7 @@ handle_fragment_box (void *cls,
3096 finish_cmc_handling (cmc); 3097 finish_cmc_handling (cmc);
3097 return; 3098 return;
3098 } 3099 }
3099 3100
3100 /* reassemble */ 3101 /* reassemble */
3101 fsize = ntohs (fb->header.size) - sizeof (*fb); 3102 fsize = ntohs (fb->header.size) - sizeof (*fb);
3102 frag_off = ntohs (fb->frag_off); 3103 frag_off = ntohs (fb->frag_off);
@@ -3112,7 +3113,7 @@ handle_fragment_box (void *cls,
3112 rc->msg_missing--; 3113 rc->msg_missing--;
3113 } 3114 }
3114 } 3115 }
3115 3116
3116 /* Compute cummulative ACK */ 3117 /* Compute cummulative ACK */
3117 frag_uuid = ntohl (fb->frag_uuid); 3118 frag_uuid = ntohl (fb->frag_uuid);
3118 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag); 3119 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
@@ -3151,7 +3152,7 @@ handle_fragment_box (void *cls,
3151 ( (rc->frag_uuid < frag_uuid + 64) && 3152 ( (rc->frag_uuid < frag_uuid + 64) &&
3152 (rc->extra_acks == (rc->extra_acks & ~ ((1LLU << (64 - (rc->frag_uuid - frag_uuid))) - 1LLU))) ) ) ) 3153 (rc->extra_acks == (rc->extra_acks & ~ ((1LLU << (64 - (rc->frag_uuid - frag_uuid))) - 1LLU))) ) ) )
3153 { 3154 {
3154 /* can fit ack by shifting extra acks and starting at 3155 /* can fit ack by shifting extra acks and starting at
3155 frag_uid, test above esured that the bits we will 3156 frag_uid, test above esured that the bits we will
3156 shift 'extra_acks' by are all zero. */ 3157 shift 'extra_acks' by are all zero. */
3157 rc->extra_acks <<= (rc->frag_uuid - frag_uuid); 3158 rc->extra_acks <<= (rc->frag_uuid - frag_uuid);
@@ -3162,8 +3163,8 @@ handle_fragment_box (void *cls,
3162 if (65 == rc->num_acks) /* FIXME: maybe use smaller threshold? This is very aggressive. */ 3163 if (65 == rc->num_acks) /* FIXME: maybe use smaller threshold? This is very aggressive. */
3163 ack_now = GNUNET_YES; /* maximum acks received */ 3164 ack_now = GNUNET_YES; /* maximum acks received */
3164 // FIXME: possibly also ACK based on RTT (but for that we'd need to 3165 // FIXME: possibly also ACK based on RTT (but for that we'd need to
3165 // determine the session used for the ACK first!) 3166 // determine the session used for the ACK first!)
3166 3167
3167 /* is reassembly complete? */ 3168 /* is reassembly complete? */
3168 if (0 != rc->msg_missing) 3169 if (0 != rc->msg_missing)
3169 { 3170 {
@@ -3187,7 +3188,7 @@ handle_fragment_box (void *cls,
3187 msg); 3188 msg);
3188 /* FIXME: really free here? Might be bad if fragments are still 3189 /* FIXME: really free here? Might be bad if fragments are still
3189 en-route and we forget that we finished this reassembly immediately! 3190 en-route and we forget that we finished this reassembly immediately!
3190 -> keep around until timeout? 3191 -> keep around until timeout?
3191 -> shorten timeout based on ACK? */ 3192 -> shorten timeout based on ACK? */
3192 free_reassembly_context (rc); 3193 free_reassembly_context (rc);
3193} 3194}
@@ -3204,7 +3205,7 @@ handle_fragment_ack (void *cls,
3204 const struct TransportFragmentAckMessage *fa) 3205 const struct TransportFragmentAckMessage *fa)
3205{ 3206{
3206 struct CommunicatorMessageContext *cmc = cls; 3207 struct CommunicatorMessageContext *cmc = cls;
3207 3208
3208 // FIXME: do work: identify original message; then identify fragments being acked; 3209 // FIXME: do work: identify original message; then identify fragments being acked;
3209 // remove those from the tree to prevent retransmission; 3210 // remove those from the tree to prevent retransmission;
3210 // compute RTT 3211 // compute RTT
@@ -3248,10 +3249,10 @@ handle_reliability_box (void *cls,
3248 3249
3249 /* FIXME: implement cummulative ACKs and ack_countdown, 3250 /* FIXME: implement cummulative ACKs and ack_countdown,
3250 then setting the avg_ack_delay field below: */ 3251 then setting the avg_ack_delay field below: */
3251 ack = GNUNET_malloc (sizeof (*ack) + 3252 ack = GNUNET_malloc (sizeof (*ack) +
3252 sizeof (struct GNUNET_ShortHashCode)); 3253 sizeof (struct GNUNET_ShortHashCode));
3253 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK); 3254 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
3254 ack->header.size = htons (sizeof (*ack) + 3255 ack->header.size = htons (sizeof (*ack) +
3255 sizeof (struct GNUNET_ShortHashCode)); 3256 sizeof (struct GNUNET_ShortHashCode));
3256 memcpy (&ack[1], 3257 memcpy (&ack[1],
3257 &rb->msg_uuid, 3258 &rb->msg_uuid,
@@ -3276,7 +3277,7 @@ handle_reliability_ack (void *cls,
3276 const struct TransportReliabilityAckMessage *ra) 3277 const struct TransportReliabilityAckMessage *ra)
3277{ 3278{
3278 struct CommunicatorMessageContext *cmc = cls; 3279 struct CommunicatorMessageContext *cmc = cls;
3279 3280
3280 // FIXME: do work: find message that was acknowledged, and 3281 // FIXME: do work: find message that was acknowledged, and
3281 // remove from transmission queue; update RTT. 3282 // remove from transmission queue; update RTT.
3282 finish_cmc_handling (cmc); 3283 finish_cmc_handling (cmc);
@@ -3331,7 +3332,7 @@ handle_backchannel_encapsulation (void *cls,
3331 // FIXME: check HMAC 3332 // FIXME: check HMAC
3332 // FIXME: decrypt payload 3333 // FIXME: decrypt payload
3333 // FIXME: forward to specified communicator! 3334 // FIXME: forward to specified communicator!
3334 // (using GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING) 3335 // (using GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING)
3335 finish_cmc_handling (cmc); 3336 finish_cmc_handling (cmc);
3336} 3337}
3337 3338
@@ -3388,7 +3389,7 @@ handle_dv_learn (void *cls,
3388 const struct TransportDVLearn *dvl) 3389 const struct TransportDVLearn *dvl)
3389{ 3390{
3390 struct CommunicatorMessageContext *cmc = cls; 3391 struct CommunicatorMessageContext *cmc = cls;
3391 3392
3392 // FIXME: learn path from DV message (if bi-directional flags are set) 3393 // FIXME: learn path from DV message (if bi-directional flags are set)
3393 // FIXME: expand DV message, forward on (unless path is getting too long) 3394 // FIXME: expand DV message, forward on (unless path is getting too long)
3394 finish_cmc_handling (cmc); 3395 finish_cmc_handling (cmc);
@@ -3419,7 +3420,7 @@ check_dv_box (void *cls,
3419 return GNUNET_SYSERR; 3420 return GNUNET_SYSERR;
3420 } 3421 }
3421 isize = ntohs (inbox->size); 3422 isize = ntohs (inbox->size);
3422 if (size != sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize) 3423 if (size != sizeof (*dvb) + num_hops * sizeof (struct GNUNET_PeerIdentity) + isize)
3423 { 3424 {
3424 GNUNET_break_op (0); 3425 GNUNET_break_op (0);
3425 return GNUNET_SYSERR; 3426 return GNUNET_SYSERR;
@@ -3455,14 +3456,14 @@ handle_dv_box (void *cls,
3455 { 3456 {
3456 // FIXME: if we are not the target, shorten path and forward along. 3457 // FIXME: if we are not the target, shorten path and forward along.
3457 // Try from the _end_ of hops array if we know the given 3458 // Try from the _end_ of hops array if we know the given
3458 // neighbour (shortening the path!). 3459 // neighbour (shortening the path!).
3459 // NOTE: increment total_hops! 3460 // NOTE: increment total_hops!
3460 finish_cmc_handling (cmc); 3461 finish_cmc_handling (cmc);
3461 return; 3462 return;
3462 } 3463 }
3463 /* We are the target. Unbox and handle message. */ 3464 /* We are the target. Unbox and handle message. */
3464 cmc->im.sender = dvb->origin; 3465 cmc->im.sender = dvb->origin;
3465 cmc->total_hops = ntohs (dvb->total_hops); 3466 cmc->total_hops = ntohs (dvb->total_hops);
3466 demultiplex_with_cmc (cmc, 3467 demultiplex_with_cmc (cmc,
3467 inbox); 3468 inbox);
3468} 3469}
@@ -3516,7 +3517,7 @@ handle_incoming_msg (void *cls,
3516 * 3517 *
3517 * @param cmc context for demultiplexing 3518 * @param cmc context for demultiplexing
3518 * @param msg message to demultiplex 3519 * @param msg message to demultiplex
3519 */ 3520 */
3520static void 3521static void
3521demultiplex_with_cmc (struct CommunicatorMessageContext *cmc, 3522demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
3522 const struct GNUNET_MessageHeader *msg) 3523 const struct GNUNET_MessageHeader *msg)
@@ -3606,7 +3607,7 @@ tracker_update_in_cb (void *cls)
3606 struct GNUNET_ATS_Session *queue = cls; 3607 struct GNUNET_ATS_Session *queue = cls;
3607 struct GNUNET_TIME_Relative in_delay; 3608 struct GNUNET_TIME_Relative in_delay;
3608 unsigned int rsize; 3609 unsigned int rsize;
3609 3610
3610 rsize = (0 == queue->mtu) ? IN_PACKET_SIZE_WITHOUT_MTU : queue->mtu; 3611 rsize = (0 == queue->mtu) ? IN_PACKET_SIZE_WITHOUT_MTU : queue->mtu;
3611 in_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_in, 3612 in_delay = GNUNET_BANDWIDTH_tracker_get_delay (&queue->tracker_in,
3612 rsize); 3613 rsize);
@@ -3632,7 +3633,7 @@ set_pending_message_uuid (struct PendingMessage *pm)
3632 3633
3633 3634
3634/** 3635/**
3635 * Fragment the given @a pm to the given @a mtu. Adds 3636 * Fragment the given @a pm to the given @a mtu. Adds
3636 * additional fragments to the neighbour as well. If the 3637 * additional fragments to the neighbour as well. If the
3637 * @a mtu is too small, generates and error for the @a pm 3638 * @a mtu is too small, generates and error for the @a pm
3638 * and returns NULL. 3639 * and returns NULL.
@@ -3648,7 +3649,7 @@ fragment_message (struct PendingMessage *pm,
3648 struct PendingMessage *ff; 3649 struct PendingMessage *ff;
3649 3650
3650 set_pending_message_uuid (pm); 3651 set_pending_message_uuid (pm);
3651 3652
3652 /* This invariant is established in #handle_add_queue_message() */ 3653 /* This invariant is established in #handle_add_queue_message() */
3653 GNUNET_assert (mtu > sizeof (struct TransportFragmentBox)); 3654 GNUNET_assert (mtu > sizeof (struct TransportFragmentBox));
3654 3655
@@ -3756,7 +3757,7 @@ reliability_box_message (struct PendingMessage *pm)
3756 if (NULL != pm->bpm) 3757 if (NULL != pm->bpm)
3757 return pm->bpm; /* already computed earlier: do nothing */ 3758 return pm->bpm; /* already computed earlier: do nothing */
3758 GNUNET_assert (NULL == pm->head_frag); 3759 GNUNET_assert (NULL == pm->head_frag);
3759 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX) 3760 if (pm->bytes_msg + sizeof (rbox) > UINT16_MAX)
3760 { 3761 {
3761 /* failed hard */ 3762 /* failed hard */
3762 GNUNET_break (0); 3763 GNUNET_break (0);
@@ -3766,7 +3767,7 @@ reliability_box_message (struct PendingMessage *pm)
3766 return NULL; 3767 return NULL;
3767 } 3768 }
3768 bpm = GNUNET_malloc (sizeof (struct PendingMessage) + 3769 bpm = GNUNET_malloc (sizeof (struct PendingMessage) +
3769 sizeof (rbox) + 3770 sizeof (rbox) +
3770 pm->bytes_msg); 3771 pm->bytes_msg);
3771 bpm->target = pm->target; 3772 bpm->target = pm->target;
3772 bpm->frag_parent = pm; 3773 bpm->frag_parent = pm;
@@ -3796,12 +3797,12 @@ reliability_box_message (struct PendingMessage *pm)
3796 3797
3797/** 3798/**
3798 * We believe we are ready to transmit a message on a queue. Double-checks 3799 * We believe we are ready to transmit a message on a queue. Double-checks
3799 * with the queue's "tracker_out" and then gives the message to the 3800 * with the queue's "tracker_out" and then gives the message to the
3800 * communicator for transmission (updating the tracker, and re-scheduling 3801 * communicator for transmission (updating the tracker, and re-scheduling
3801 * itself if applicable). 3802 * itself if applicable).
3802 * 3803 *
3803 * @param cls the `struct GNUNET_ATS_Session` to process transmissions for 3804 * @param cls the `struct GNUNET_ATS_Session` to process transmissions for
3804 */ 3805 */
3805static void 3806static void
3806transmit_on_queue (void *cls) 3807transmit_on_queue (void *cls)
3807{ 3808{
@@ -3818,7 +3819,7 @@ transmit_on_queue (void *cls)
3818 if (NULL == (pm = n->pending_msg_head)) 3819 if (NULL == (pm = n->pending_msg_head))
3819 { 3820 {
3820 /* no message pending, nothing to do here! */ 3821 /* no message pending, nothing to do here! */
3821 return; 3822 return;
3822 } 3823 }
3823 schedule_transmit_on_queue (queue); 3824 schedule_transmit_on_queue (queue);
3824 if (NULL != queue->transmit_task) 3825 if (NULL != queue->transmit_task)
@@ -3874,7 +3875,7 @@ transmit_on_queue (void *cls)
3874 queue->tc->details.communicator.total_queue_length++; 3875 queue->tc->details.communicator.total_queue_length++;
3875 GNUNET_MQ_send (queue->tc->mq, 3876 GNUNET_MQ_send (queue->tc->mq,
3876 env); 3877 env);
3877 3878
3878 // FIXME: do something similar to the logic below 3879 // FIXME: do something similar to the logic below
3879 // in defragmentation / reliability ACK handling! 3880 // in defragmentation / reliability ACK handling!
3880 3881
@@ -3892,7 +3893,7 @@ transmit_on_queue (void *cls)
3892 (PMT_FRAGMENT_BOX == s->pmt) ) 3893 (PMT_FRAGMENT_BOX == s->pmt) )
3893 { 3894 {
3894 struct PendingMessage *pos; 3895 struct PendingMessage *pos;
3895 3896
3896 /* Fragment sent over reliabile channel */ 3897 /* Fragment sent over reliabile channel */
3897 free_fragment_tree (s); 3898 free_fragment_tree (s);
3898 pos = s->frag_parent; 3899 pos = s->frag_parent;
@@ -3912,9 +3913,9 @@ transmit_on_queue (void *cls)
3912 pos->head_frag, 3913 pos->head_frag,
3913 pos->tail_frag, 3914 pos->tail_frag,
3914 s); 3915 s);
3915 GNUNET_free (s); 3916 GNUNET_free (s);
3916 } 3917 }
3917 3918
3918 /* Was this the last applicable fragmment? */ 3919 /* Was this the last applicable fragmment? */
3919 if ( (NULL == pm->head_frag) && 3920 if ( (NULL == pm->head_frag) &&
3920 (pm->frag_off == pm->bytes_msg) ) 3921 (pm->frag_off == pm->bytes_msg) )
@@ -3981,7 +3982,7 @@ transmit_on_queue (void *cls)
3981 s); 3982 s);
3982 } 3983 }
3983 } 3984 }
3984 3985
3985 /* finally, re-schedule queue transmission task itself */ 3986 /* finally, re-schedule queue transmission task itself */
3986 schedule_transmit_on_queue (queue); 3987 schedule_transmit_on_queue (queue);
3987} 3988}
@@ -4023,13 +4024,13 @@ tracker_excess_out_cb (void *cls)
4023{ 4024{
4024 /* FIXME: trigger excess bandwidth report to core? Right now, 4025 /* FIXME: trigger excess bandwidth report to core? Right now,
4025 this is done internally within transport_api2_core already, 4026 this is done internally within transport_api2_core already,
4026 but we probably want to change the logic and trigger it 4027 but we probably want to change the logic and trigger it
4027 from here via a message instead! */ 4028 from here via a message instead! */
4028 /* TODO: maybe inform ATS at this point? */ 4029 /* TODO: maybe inform ATS at this point? */
4029 GNUNET_STATISTICS_update (GST_stats, 4030 GNUNET_STATISTICS_update (GST_stats,
4030 "# Excess outbound bandwidth reported", 4031 "# Excess outbound bandwidth reported",
4031 1, 4032 1,
4032 GNUNET_NO); 4033 GNUNET_NO);
4033} 4034}
4034 4035
4035 4036
@@ -4047,7 +4048,7 @@ tracker_excess_in_cb (void *cls)
4047 GNUNET_STATISTICS_update (GST_stats, 4048 GNUNET_STATISTICS_update (GST_stats,
4048 "# Excess inbound bandwidth reported", 4049 "# Excess inbound bandwidth reported",
4049 1, 4050 1,
4050 GNUNET_NO); 4051 GNUNET_NO);
4051} 4052}
4052 4053
4053 4054
@@ -4126,7 +4127,7 @@ handle_add_queue_message (void *cls,
4126 .nt = queue->nt, 4127 .nt = queue->nt,
4127 .cc = tc->details.communicator.cc 4128 .cc = tc->details.communicator.cc
4128 }; 4129 };
4129 4130
4130 queue->sr = GNUNET_ATS_session_add (ats, 4131 queue->sr = GNUNET_ATS_session_add (ats,
4131 &neighbour->pid, 4132 &neighbour->pid,
4132 queue->address, 4133 queue->address,
@@ -4224,7 +4225,7 @@ handle_send_message_ack (void *cls,
4224{ 4225{
4225 struct TransportClient *tc = cls; 4226 struct TransportClient *tc = cls;
4226 struct QueueEntry *queue; 4227 struct QueueEntry *queue;
4227 4228
4228 if (CT_COMMUNICATOR != tc->type) 4229 if (CT_COMMUNICATOR != tc->type)
4229 { 4230 {
4230 GNUNET_break (0); 4231 GNUNET_break (0);
@@ -4251,12 +4252,12 @@ handle_send_message_ack (void *cls,
4251 queue = qe; 4252 queue = qe;
4252 break; 4253 break;
4253 } 4254 }
4254 break; 4255 break;
4255 } 4256 }
4256 if (NULL == queue) 4257 if (NULL == queue)
4257 { 4258 {
4258 /* this should never happen */ 4259 /* this should never happen */
4259 GNUNET_break (0); 4260 GNUNET_break (0);
4260 GNUNET_SERVICE_client_drop (tc->client); 4261 GNUNET_SERVICE_client_drop (tc->client);
4261 return; 4262 return;
4262 } 4263 }
@@ -4286,10 +4287,10 @@ handle_send_message_ack (void *cls,
4286 GNUNET_STATISTICS_update (GST_stats, 4287 GNUNET_STATISTICS_update (GST_stats,
4287 "# Transmission throttled due to session queue limit", 4288 "# Transmission throttled due to session queue limit",
4288 -1, 4289 -1,
4289 GNUNET_NO); 4290 GNUNET_NO);
4290 schedule_transmit_on_queue (queue->session); 4291 schedule_transmit_on_queue (queue->session);
4291 } 4292 }
4292 4293
4293 /* TODO: we also should react on the status! */ 4294 /* TODO: we also should react on the status! */
4294 // FIXME: this probably requires queue->pm = s assignment! 4295 // FIXME: this probably requires queue->pm = s assignment!
4295 // FIXME: react to communicator status about transmission request. We got: 4296 // FIXME: react to communicator status about transmission request. We got:
@@ -4452,7 +4453,7 @@ ats_suggestion_cb (void *cls,
4452 GNUNET_STATISTICS_update (GST_stats, 4453 GNUNET_STATISTICS_update (GST_stats,
4453 "# ATS suggestions ignored due to missing communicator", 4454 "# ATS suggestions ignored due to missing communicator",
4454 1, 4455 1,
4455 GNUNET_NO); 4456 GNUNET_NO);
4456 return; 4457 return;
4457 } 4458 }
4458 /* forward suggestion for queue creation to communicator */ 4459 /* forward suggestion for queue creation to communicator */
@@ -4481,7 +4482,7 @@ ats_suggestion_cb (void *cls,
4481 * 4482 *
4482 * @param cls the `struct TransportClient` 4483 * @param cls the `struct TransportClient`
4483 * @param cqr confirmation message 4484 * @param cqr confirmation message
4484 */ 4485 */
4485static void 4486static void
4486handle_queue_create_ok (void *cls, 4487handle_queue_create_ok (void *cls,
4487 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr) 4488 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
@@ -4501,7 +4502,7 @@ handle_queue_create_ok (void *cls,
4501 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 4502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4502 "Request #%u for communicator to create queue succeeded\n", 4503 "Request #%u for communicator to create queue succeeded\n",
4503 (unsigned int) ntohs (cqr->request_id)); 4504 (unsigned int) ntohs (cqr->request_id));
4504 GNUNET_SERVICE_client_continue (tc->client); 4505 GNUNET_SERVICE_client_continue (tc->client);
4505} 4506}
4506 4507
4507 4508
@@ -4512,7 +4513,7 @@ handle_queue_create_ok (void *cls,
4512 * 4513 *
4513 * @param cls the `struct TransportClient` 4514 * @param cls the `struct TransportClient`
4514 * @param cqr failure message 4515 * @param cqr failure message
4515 */ 4516 */
4516static void 4517static void
4517handle_queue_create_fail (void *cls, 4518handle_queue_create_fail (void *cls,
4518 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr) 4519 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
@@ -4532,7 +4533,61 @@ handle_queue_create_fail (void *cls,
4532 "# ATS suggestions failed in queue creation at communicator", 4533 "# ATS suggestions failed in queue creation at communicator",
4533 1, 4534 1,
4534 GNUNET_NO); 4535 GNUNET_NO);
4535 GNUNET_SERVICE_client_continue (tc->client); 4536 GNUNET_SERVICE_client_continue (tc->client);
4537}
4538
4539
4540/**
4541 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY
4542 * messages. We do nothing here, real verification is done later.
4543 *
4544 * @param cls a `struct TransportClient *`
4545 * @param msg message to verify
4546 * @return #GNUNET_OK
4547 */
4548static int
4549check_address_consider_verify (void *cls,
4550 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
4551{
4552 (void) cls;
4553 (void) hdr;
4554 return GNUNET_OK;
4555}
4556
4557
4558/**
4559 * Given another peers address, consider checking it for validity
4560 * and then adding it to the Peerstore.
4561 *
4562 * @param cls a `struct TransportClient`
4563 * @param hdr message containing the raw address data and
4564 * signature in the body, see #GNUNET_HELLO_extract_address()
4565 */
4566static void
4567handle_address_consider_verify (void *cls,
4568 const struct GNUNET_TRANSPORT_AddressToVerify *hdr)
4569{
4570 char *address;
4571 enum GNUNET_NetworkType nt;
4572 struct GNUNET_TIME_Absolute expiration;
4573
4574 (void) cls;
4575 // FIXME: pre-check: do we know this address already?
4576 // FIXME: pre-check: rate-limit signature verification / validation!
4577 address = GNUNET_HELLO_extract_address (&hdr[1],
4578 ntohs (hdr->header.size) - sizeof (*hdr),
4579 &hdr->peer,
4580 &nt,
4581 &expiration);
4582 if (NULL == address)
4583 {
4584 GNUNET_break_op (0);
4585 return;
4586 }
4587 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
4588 return; /* expired */
4589 // FIXME: do begin actual verification here!
4590 GNUNET_free (address);
4536} 4591}
4537 4592
4538 4593
@@ -4775,6 +4830,10 @@ GNUNET_SERVICE_MAIN
4775 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP, 4830 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
4776 struct GNUNET_TRANSPORT_AddQueueMessage, 4831 struct GNUNET_TRANSPORT_AddQueueMessage,
4777 NULL), 4832 NULL),
4833 GNUNET_MQ_hd_var_size (address_consider_verify,
4834 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY,
4835 struct GNUNET_TRANSPORT_AddressToVerify,
4836 NULL),
4778 GNUNET_MQ_hd_fixed_size (del_queue_message, 4837 GNUNET_MQ_hd_fixed_size (del_queue_message,
4779 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN, 4838 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
4780 struct GNUNET_TRANSPORT_DelQueueMessage, 4839 struct GNUNET_TRANSPORT_DelQueueMessage,
diff --git a/src/transport/gnunet-service-transport_validation.c b/src/transport/gnunet-service-transport_validation.c
index 8d22d0c7a..6abe8d2d2 100644
--- a/src/transport/gnunet-service-transport_validation.c
+++ b/src/transport/gnunet-service-transport_validation.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -1115,7 +1115,8 @@ GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender,
1115 } 1115 }
1116 ping = (const struct TransportPingMessage *) hdr; 1116 ping = (const struct TransportPingMessage *) hdr;
1117 if (0 != 1117 if (0 !=
1118 memcmp (&ping->target, &GST_my_identity, 1118 memcmp (&ping->target,
1119 &GST_my_identity,
1119 sizeof (struct GNUNET_PeerIdentity))) 1120 sizeof (struct GNUNET_PeerIdentity)))
1120 { 1121 {
1121 GNUNET_STATISTICS_update (GST_stats, 1122 GNUNET_STATISTICS_update (GST_stats,
diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c
index d93c4423c..a0dd80617 100644
--- a/src/transport/plugin_transport_tcp.c
+++ b/src/transport/plugin_transport_tcp.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -1471,6 +1471,12 @@ tcp_nat_port_map_callback (void *cls,
1471 args = sizeof (t4); 1471 args = sizeof (t4);
1472 break; 1472 break;
1473 case AF_INET6: 1473 case AF_INET6:
1474 if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr))
1475 {
1476 /* skip link local, we don't allow them in
1477 #tcp_plugin_check_address() */
1478 return;
1479 }
1474 GNUNET_assert(addrlen == sizeof(struct sockaddr_in6)); 1480 GNUNET_assert(addrlen == sizeof(struct sockaddr_in6));
1475 memset (&t6, 0, sizeof(t6)); 1481 memset (&t6, 0, sizeof(t6));
1476 GNUNET_memcpy (&t6.ipv6_addr, 1482 GNUNET_memcpy (&t6.ipv6_addr,
diff --git a/src/transport/transport.h b/src/transport/transport.h
index 931ba4810..c0e02c3d9 100644
--- a/src/transport/transport.h
+++ b/src/transport/transport.h
@@ -1081,6 +1081,32 @@ struct GNUNET_TRANSPORT_MonitorData
1081 1081
1082}; 1082};
1083 1083
1084
1085/**
1086 * Request to verify address.
1087 */
1088struct GNUNET_TRANSPORT_AddressToVerify
1089{
1090
1091 /**
1092 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY.
1093 */
1094 struct GNUNET_MessageHeader header;
1095
1096 /**
1097 * Reserved. 0.
1098 */
1099 uint32_t reserved;
1100
1101 /**
1102 * Peer the address is from.
1103 */
1104 struct GNUNET_PeerIdentity peer;
1105
1106 /* followed by variable-size raw address */
1107};
1108
1109
1084#endif 1110#endif
1085 1111
1086GNUNET_NETWORK_STRUCT_END 1112GNUNET_NETWORK_STRUCT_END
diff --git a/src/transport/transport_api2_address.c b/src/transport/transport_api2_address.c
new file mode 100644
index 000000000..1ff599efb
--- /dev/null
+++ b/src/transport/transport_api2_address.c
@@ -0,0 +1,249 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013, 2016, 2018, 2019 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 transport/transport_api2_address.c
23 * @brief library to inform the transport service about addresses to be validated
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_constants.h"
29#include "gnunet_protocols.h"
30#include "gnunet_transport_address_service.h"
31#include "gnunet_ats_transport_service.h"
32#include "transport.h"
33
34#define LOG(kind,...) GNUNET_log_from (kind, "transport-api-address",__VA_ARGS__)
35
36
37/**
38 * Handle for the transport service (includes all of the
39 * state for the transport service).
40 */
41struct GNUNET_TRANSPORT_AddressHandle
42{
43
44 /**
45 * My client connection to the transport service.
46 */
47 struct GNUNET_MQ_Handle *mq;
48
49 /**
50 * My configuration.
51 */
52 const struct GNUNET_CONFIGURATION_Handle *cfg;
53
54 /**
55 * ID of the task trying to reconnect to the service.
56 */
57 struct GNUNET_SCHEDULER_Task *reconnect_task;
58
59 /**
60 * Delay until we try to reconnect.
61 */
62 struct GNUNET_TIME_Relative reconnect_delay;
63
64};
65
66
67/**
68 * Function that will schedule the job that will try
69 * to connect us again to the client.
70 *
71 * @param h transport service to reconnect
72 */
73static void
74disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_AddressHandle *h);
75
76
77/**
78 * Generic error handler, called with the appropriate
79 * error code and the same closure specified at the creation of
80 * the message queue.
81 * Not every message queue implementation supports an error handler.
82 *
83 * @param cls closure with the `struct GNUNET_TRANSPORT_AddressHandle *`
84 * @param error error code
85 */
86static void
87mq_error_handler (void *cls,
88 enum GNUNET_MQ_Error error)
89{
90 struct GNUNET_TRANSPORT_AddressHandle *h = cls;
91
92 LOG (GNUNET_ERROR_TYPE_DEBUG,
93 "Error receiving from transport service, disconnecting temporarily.\n");
94 disconnect_and_schedule_reconnect (h);
95}
96
97
98/**
99 * Try again to connect to transport service.
100 *
101 * @param cls the handle to the transport service
102 */
103static void
104reconnect (void *cls)
105{
106 struct GNUNET_TRANSPORT_AddressHandle *h = cls;
107 struct GNUNET_MQ_MessageHandler handlers[] = {
108 GNUNET_MQ_handler_end ()
109 };
110
111 h->reconnect_task = NULL;
112 LOG (GNUNET_ERROR_TYPE_DEBUG,
113 "Connecting to transport service.\n");
114 GNUNET_assert (NULL == h->mq);
115 h->mq = GNUNET_CLIENT_connect (h->cfg,
116 "transport",
117 handlers,
118 &mq_error_handler,
119 h);
120}
121
122
123/**
124 * Disconnect from the transport service.
125 *
126 * @param h transport service to disconnect
127 */
128static void
129disconnect (struct GNUNET_TRANSPORT_AddressHandle *h)
130{
131 if (NULL != h->mq)
132 {
133 GNUNET_MQ_destroy (h->mq);
134 h->mq = NULL;
135 }
136}
137
138
139/**
140 * Function that will schedule the job that will try
141 * to connect us again to the client.
142 *
143 * @param h transport service to reconnect
144 */
145static void
146disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_AddressHandle *h)
147{
148 GNUNET_assert (NULL == h->reconnect_task);
149 disconnect (h);
150 LOG (GNUNET_ERROR_TYPE_DEBUG,
151 "Scheduling task to reconnect to transport service in %s.\n",
152 GNUNET_STRINGS_relative_time_to_string (h->reconnect_delay,
153 GNUNET_YES));
154 h->reconnect_task =
155 GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
156 &reconnect,
157 h);
158 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
159}
160
161
162/**
163 * Connect to the transport service.
164 *
165 * @param cfg configuration to use
166 * @return NULL on error
167 */
168struct GNUNET_TRANSPORT_AddressHandle *
169GNUNET_TRANSPORT_address_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
170{
171 struct GNUNET_TRANSPORT_AddressHandle *h;
172
173 h = GNUNET_new (struct GNUNET_TRANSPORT_AddressHandle);
174 h->cfg = cfg;
175 h->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
176 LOG (GNUNET_ERROR_TYPE_DEBUG,
177 "Connecting to transport service\n");
178 reconnect (h);
179 if (NULL == h->mq)
180 {
181 GNUNET_free (h);
182 return NULL;
183 }
184 return h;
185}
186
187
188/**
189 * Disconnect from the transport service.
190 *
191 * @param handle handle to the service as returned from #GNUNET_TRANSPORT_address_connect()
192 */
193void
194GNUNET_TRANSPORT_address_disconnect (struct GNUNET_TRANSPORT_AddressHandle *handle)
195{
196 LOG (GNUNET_ERROR_TYPE_DEBUG,
197 "Transport disconnect called!\n");
198 /* this disconnects all neighbours... */
199 disconnect (handle);
200 /* and now we stop trying to connect again... */
201 if (NULL != handle->reconnect_task)
202 {
203 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
204 handle->reconnect_task = NULL;
205 }
206 GNUNET_free (handle);
207}
208
209
210/**
211 * The client has learned about a possible address for peer @a pid
212 * (i.e. via broadcast, multicast, DHT, ...). The transport service
213 * should consider validating it. Note that the plugin is NOT expected
214 * to have verified the signature, the transport service must decide
215 * whether to check the signature.
216 *
217 * While the notification is sent to @a ch asynchronously, this API
218 * does not return a handle as the delivery of addresses is simply
219 * unreliable, and if @a ch is down, the data provided will simply be
220 * lost.
221 *
222 * @param ch communicator handle
223 * @param pid peer the address is for
224 * @param raw raw address data
225 * @param raw_size number of bytes in @a raw
226 */
227void
228GNUNET_TRANSPORT_address_try (struct GNUNET_TRANSPORT_AddressHandle *ch,
229 const struct GNUNET_PeerIdentity *pid,
230 const void *raw,
231 const size_t raw_size)
232{
233 struct GNUNET_MQ_Envelope *env;
234 struct GNUNET_TRANSPORT_AddressToVerify *hdr;
235
236 env = GNUNET_MQ_msg_extra (hdr,
237 raw_size,
238 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY);
239 hdr->peer = *pid;
240 memcpy (&hdr[1],
241 raw,
242 raw_size);
243 GNUNET_MQ_send (ch->mq,
244 env);
245}
246
247
248
249/* end of transport_api2_address.c */
diff --git a/src/transport/transport_api_core.c b/src/transport/transport_api_core.c
index b144ef6b6..75287b5e7 100644
--- a/src/transport/transport_api_core.c
+++ b/src/transport/transport_api_core.c
@@ -558,7 +558,7 @@ handle_connect (void *cls,
558 &cim->id); 558 &cim->id);
559 if (NULL != n) 559 if (NULL != n)
560 { 560 {
561 GNUNET_break (0); 561 GNUNET_break (0); /* FIXME: this assertion seems to fail sometimes!? */
562 disconnect_and_schedule_reconnect (h); 562 disconnect_and_schedule_reconnect (h);
563 return; 563 return;
564 } 564 }
diff --git a/src/util/.gitignore b/src/util/.gitignore
index 7b190ca76..dfa6c7947 100644
--- a/src/util/.gitignore
+++ b/src/util/.gitignore
@@ -73,3 +73,4 @@ test_hexcoder
73test_regex 73test_regex
74test_tun 74test_tun
75gnunet-timeout 75gnunet-timeout
76python27_location
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 625ff87a2..0ba06f4bb 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -41,7 +41,7 @@ if USE_COVERAGE
41endif 41endif
42 42
43if ENABLE_BENCHMARK 43if ENABLE_BENCHMARK
44 BENCHMARK = benchmark.c 44 BENCHMARK = benchmark.c benchmark.h
45 PTHREAD = -lpthread 45 PTHREAD = -lpthread
46endif 46endif
47 47
@@ -225,8 +225,13 @@ gnunet_timeout_SOURCES = \
225 gnunet-timeout-w32.c 225 gnunet-timeout-w32.c
226endif 226endif
227 227
228# This is horrible, but compared to the alternatives and the solution
229# which preceded this it is a good compromise and good enough for one
230# file. Everyone else is invited to patch it locally.
228 231
229do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' 232xENV=$(shell which env)
233
234do_subst = $(SED) -e 's,[@]ENV[@],${xENV},g'
230 235
231gnunet-qr: gnunet-qr.py.in Makefile 236gnunet-qr: gnunet-qr.py.in Makefile
232 $(do_subst) < $(top_srcdir)/src/util/gnunet-qr.py.in > gnunet-qr 237 $(do_subst) < $(top_srcdir)/src/util/gnunet-qr.py.in > gnunet-qr
diff --git a/src/util/container_multihashmap.c b/src/util/container_multihashmap.c
index cf5c2a334..7605ea151 100644
--- a/src/util/container_multihashmap.c
+++ b/src/util/container_multihashmap.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -417,7 +417,7 @@ GNUNET_CONTAINER_multihashmap_iterate (struct GNUNET_CONTAINER_MultiHashMap *map
417 } 417 }
418 } 418 }
419 } 419 }
420 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE); 420 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
421 return count; 421 return count;
422} 422}
423 423
@@ -764,18 +764,19 @@ grow (struct GNUNET_CONTAINER_MultiHashMap *map)
764 unsigned int new_len; 764 unsigned int new_len;
765 unsigned int idx; 765 unsigned int idx;
766 766
767 map->modification_counter++;
768
769 old_map = map->map; 767 old_map = map->map;
770 old_len = map->map_length; 768 old_len = map->map_length;
769 GNUNET_assert (0 != old_len);
771 new_len = old_len * 2; 770 new_len = old_len * 2;
772 /* if we would exceed heap size limit for the _first_ time, 771 if (0 == new_len) /* 2^31 * 2 == 0 */
773 try staying just below the limit */ 772 new_len = old_len; /* never use 0 */
774 if ( (new_len * sizeof (union MapEntry) > GNUNET_MAX_MALLOC_CHECKED) && 773 if (new_len == old_len)
775 ((old_len+1) * sizeof (union MapEntry) < GNUNET_MAX_MALLOC_CHECKED) ) 774 return; /* nothing changed */
776 new_len = GNUNET_MAX_MALLOC_CHECKED / sizeof (union MapEntry); 775 new_map = GNUNET_malloc_large (new_len *
777 new_map = GNUNET_new_array (new_len, 776 sizeof (union MapEntry));
778 union MapEntry); 777 if (NULL == new_map)
778 return; /* grow not possible */
779 map->modification_counter++;
779 map->map_length = new_len; 780 map->map_length = new_len;
780 map->map = new_map; 781 map->map = new_map;
781 for (unsigned int i = 0; i < old_len; i++) 782 for (unsigned int i = 0; i < old_len; i++)
diff --git a/src/util/container_multihashmap32.c b/src/util/container_multihashmap32.c
index 4b19c7c10..a614c04ae 100644
--- a/src/util/container_multihashmap32.c
+++ b/src/util/container_multihashmap32.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -146,8 +146,13 @@ GNUNET_CONTAINER_multihashmap32_create (unsigned int len)
146 146
147 GNUNET_assert (len > 0); 147 GNUNET_assert (len > 0);
148 ret = GNUNET_new (struct GNUNET_CONTAINER_MultiHashMap32); 148 ret = GNUNET_new (struct GNUNET_CONTAINER_MultiHashMap32);
149 ret->map = GNUNET_new_array (len, 149 ret->map = GNUNET_malloc_large (len *
150 struct MapEntry *); 150 sizeof (struct MapEntry *));
151 if (NULL == ret->map)
152 {
153 GNUNET_free (ret);
154 return NULL;
155 }
151 ret->map_length = len; 156 ret->map_length = len;
152 return ret; 157 return ret;
153} 158}
@@ -268,7 +273,7 @@ GNUNET_CONTAINER_multihashmap32_iterate (struct GNUNET_CONTAINER_MultiHashMap32
268 e->key, 273 e->key,
269 e->value)) 274 e->value))
270 { 275 {
271 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE); 276 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
272 return GNUNET_SYSERR; 277 return GNUNET_SYSERR;
273 } 278 }
274 } 279 }
@@ -463,13 +468,18 @@ grow (struct GNUNET_CONTAINER_MultiHashMap32 *map)
463 unsigned int new_len; 468 unsigned int new_len;
464 unsigned int idx; 469 unsigned int idx;
465 470
466 map->modification_counter++;
467
468 old_map = map->map; 471 old_map = map->map;
469 old_len = map->map_length; 472 old_len = map->map_length;
470 new_len = old_len * 2; 473 new_len = old_len * 2;
471 new_map = GNUNET_new_array (new_len, 474 if (0 == new_len) /* 2^31 * 2 == 0 */
472 struct MapEntry *); 475 new_len = old_len; /* never use 0 */
476 if (new_len == old_len)
477 return; /* nothing changed */
478 new_map = GNUNET_malloc_large (new_len *
479 sizeof (struct MapEntry *));
480 if (NULL == new_map)
481 return; /* grow not possible */
482 map->modification_counter++;
473 map->map_length = new_len; 483 map->map_length = new_len;
474 map->map = new_map; 484 map->map = new_map;
475 for (unsigned int i = 0; i < old_len; i++) 485 for (unsigned int i = 0; i < old_len; i++)
diff --git a/src/util/container_multipeermap.c b/src/util/container_multipeermap.c
index 8fa23df72..613efc0a9 100644
--- a/src/util/container_multipeermap.c
+++ b/src/util/container_multipeermap.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -200,8 +200,13 @@ GNUNET_CONTAINER_multipeermap_create (unsigned int len,
200 200
201 GNUNET_assert (len > 0); 201 GNUNET_assert (len > 0);
202 map = GNUNET_new (struct GNUNET_CONTAINER_MultiPeerMap); 202 map = GNUNET_new (struct GNUNET_CONTAINER_MultiPeerMap);
203 map->map = GNUNET_new_array (len, 203 map->map = GNUNET_malloc_large (len *
204 union MapEntry); 204 sizeof (union MapEntry));
205 if (NULL == map->map)
206 {
207 GNUNET_free (map);
208 return NULL;
209 }
205 map->map_length = len; 210 map->map_length = len;
206 map->use_small_entries = do_not_copy_keys; 211 map->use_small_entries = do_not_copy_keys;
207 return map; 212 return map;
@@ -493,7 +498,7 @@ GNUNET_CONTAINER_multipeermap_remove (struct GNUNET_CONTAINER_MultiPeerMap *map,
493 if (NULL == p) 498 if (NULL == p)
494 map->map[i].bme = bme->next; 499 map->map[i].bme = bme->next;
495 else 500 else
496 p->next = bme->next; 501 p->next = bme->next;
497 update_next_cache_bme (map, 502 update_next_cache_bme (map,
498 bme); 503 bme);
499 GNUNET_free (bme); 504 GNUNET_free (bme);
@@ -685,18 +690,23 @@ grow (struct GNUNET_CONTAINER_MultiPeerMap *map)
685 unsigned int old_len; 690 unsigned int old_len;
686 unsigned int new_len; 691 unsigned int new_len;
687 unsigned int idx; 692 unsigned int idx;
688 unsigned int i;
689
690 map->modification_counter++;
691 693
692 old_map = map->map; 694 old_map = map->map;
693 old_len = map->map_length; 695 old_len = map->map_length;
696 GNUNET_assert (0 != old_len);
694 new_len = old_len * 2; 697 new_len = old_len * 2;
695 new_map = GNUNET_new_array (new_len, 698 if (0 == new_len) /* 2^31 * 2 == 0 */
696 union MapEntry); 699 new_len = old_len; /* never use 0 */
700 if (new_len == old_len)
701 return; /* nothing changed */
702 new_map = GNUNET_malloc_large (new_len *
703 sizeof (union MapEntry));
704 if (NULL == new_map)
705 return; /* grow not possible */
706 map->modification_counter++;
697 map->map_length = new_len; 707 map->map_length = new_len;
698 map->map = new_map; 708 map->map = new_map;
699 for (i = 0; i < old_len; i++) 709 for (unsigned int i = 0; i < old_len; i++)
700 { 710 {
701 if (map->use_small_entries) 711 if (map->use_small_entries)
702 { 712 {
@@ -829,7 +839,7 @@ GNUNET_CONTAINER_multipeermap_get_multiple (struct GNUNET_CONTAINER_MultiPeerMap
829 int count; 839 int count;
830 union MapEntry me; 840 union MapEntry me;
831 union MapEntry *ce; 841 union MapEntry *ce;
832 842
833 ce = &map->next_cache[map->next_cache_off]; 843 ce = &map->next_cache[map->next_cache_off];
834 GNUNET_assert (++map->next_cache_off < NEXT_CACHE_SIZE); 844 GNUNET_assert (++map->next_cache_off < NEXT_CACHE_SIZE);
835 count = 0; 845 count = 0;
@@ -903,7 +913,7 @@ GNUNET_CONTAINER_multipeermap_get_random (const struct GNUNET_CONTAINER_MultiPee
903{ 913{
904 unsigned int off; 914 unsigned int off;
905 union MapEntry me; 915 union MapEntry me;
906 916
907 if (0 == map->size) 917 if (0 == map->size)
908 return 0; 918 return 0;
909 if (NULL == it) 919 if (NULL == it)
diff --git a/src/util/container_multishortmap.c b/src/util/container_multishortmap.c
index a48581b6a..966e23d35 100644
--- a/src/util/container_multishortmap.c
+++ b/src/util/container_multishortmap.c
@@ -11,7 +11,7 @@
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 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/>. 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
@@ -183,8 +183,8 @@ struct GNUNET_CONTAINER_MultiShortmapIterator
183 * Create a multi hash map. 183 * Create a multi hash map.
184 * 184 *
185 * @param len initial size (map will grow as needed) 185 * @param len initial size (map will grow as needed)
186 * @param do_not_copy_keys GNUNET_NO is always safe and should be used by default; 186 * @param do_not_copy_keys #GNUNET_NO is always safe and should be used by default;
187 * GNUNET_YES means that on 'put', the 'key' does not have 187 * #GNUNET_YES means that on 'put', the 'key' does not have
188 * to be copied as the destination of the pointer is 188 * to be copied as the destination of the pointer is
189 * guaranteed to be life as long as the value is stored in 189 * guaranteed to be life as long as the value is stored in
190 * the hashmap. This can significantly reduce memory 190 * the hashmap. This can significantly reduce memory
@@ -202,8 +202,13 @@ GNUNET_CONTAINER_multishortmap_create (unsigned int len,
202 202
203 GNUNET_assert (len > 0); 203 GNUNET_assert (len > 0);
204 map = GNUNET_new (struct GNUNET_CONTAINER_MultiShortmap); 204 map = GNUNET_new (struct GNUNET_CONTAINER_MultiShortmap);
205 map->map = GNUNET_new_array (len, 205 map->map = GNUNET_malloc_large (len *
206 union MapEntry); 206 sizeof (union MapEntry));
207 if (NULL == map->map)
208 {
209 GNUNET_free (map);
210 return NULL;
211 }
207 map->map_length = len; 212 map->map_length = len;
208 map->use_small_entries = do_not_copy_keys; 213 map->use_small_entries = do_not_copy_keys;
209 return map; 214 return map;
@@ -355,7 +360,7 @@ GNUNET_CONTAINER_multishortmap_iterate (struct GNUNET_CONTAINER_MultiShortmap *m
355 if (map->use_small_entries) 360 if (map->use_small_entries)
356 { 361 {
357 struct SmallMapEntry *sme; 362 struct SmallMapEntry *sme;
358 363
359 ce->sme = me.sme; 364 ce->sme = me.sme;
360 while (NULL != (sme = ce->sme)) 365 while (NULL != (sme = ce->sme))
361 { 366 {
@@ -366,7 +371,7 @@ GNUNET_CONTAINER_multishortmap_iterate (struct GNUNET_CONTAINER_MultiShortmap *m
366 sme->value)) ) 371 sme->value)) )
367 { 372 {
368 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE); 373 GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
369 return GNUNET_SYSERR; 374 return GNUNET_SYSERR;
370 } 375 }
371 count++; 376 count++;
372 } 377 }
@@ -458,7 +463,7 @@ GNUNET_CONTAINER_multishortmap_remove (struct GNUNET_CONTAINER_MultiShortmap *ma
458 if (map->use_small_entries) 463 if (map->use_small_entries)
459 { 464 {
460 struct SmallMapEntry *p = NULL; 465 struct SmallMapEntry *p = NULL;
461 466
462 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next) 467 for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
463 { 468 {
464 if ((0 == memcmp (key, 469 if ((0 == memcmp (key,
@@ -482,7 +487,7 @@ GNUNET_CONTAINER_multishortmap_remove (struct GNUNET_CONTAINER_MultiShortmap *ma
482 else 487 else
483 { 488 {
484 struct BigMapEntry *p = NULL; 489 struct BigMapEntry *p = NULL;
485 490
486 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next) 491 for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
487 { 492 {
488 if ((0 == memcmp (key, 493 if ((0 == memcmp (key,
@@ -686,13 +691,18 @@ grow (struct GNUNET_CONTAINER_MultiShortmap *map)
686 unsigned int new_len; 691 unsigned int new_len;
687 unsigned int idx; 692 unsigned int idx;
688 693
689 map->modification_counter++;
690
691 old_map = map->map; 694 old_map = map->map;
692 old_len = map->map_length; 695 old_len = map->map_length;
693 new_len = old_len * 2; 696 new_len = old_len * 2;
694 new_map = GNUNET_new_array (new_len, 697 if (0 == new_len) /* 2^31 * 2 == 0 */
695 union MapEntry); 698 new_len = old_len; /* never use 0 */
699 if (new_len == old_len)
700 return; /* nothing changed */
701 new_map = GNUNET_malloc_large (new_len *
702 sizeof (union MapEntry));
703 if (NULL == new_map)
704 return; /* grow not possible */
705 map->modification_counter++;
696 map->map_length = new_len; 706 map->map_length = new_len;
697 map->map = new_map; 707 map->map = new_map;
698 for (unsigned int i = 0; i < old_len; i++) 708 for (unsigned int i = 0; i < old_len; i++)
diff --git a/src/util/dnsparser.c b/src/util/dnsparser.c
index 2baa76ef2..7546ca1e9 100644
--- a/src/util/dnsparser.c
+++ b/src/util/dnsparser.c
@@ -25,15 +25,19 @@
25 * @author Christian Grothoff 25 * @author Christian Grothoff
26 */ 26 */
27#include "platform.h" 27#include "platform.h"
28#if HAVE_LIBIDN2
28#if HAVE_IDN2_H 29#if HAVE_IDN2_H
29#include <idn2.h> 30#include <idn2.h>
30#elif HAVE_IDN2_IDN2_H 31#elif HAVE_IDN2_IDN2_H
31#include <idn2/idn2.h> 32#include <idn2/idn2.h>
32#elif HAVE_IDNA_H 33#endif
34#elif HAVE_LIBIDN
35#if HAVE_IDNA_H
33#include <idna.h> 36#include <idna.h>
34#elif HAVE_IDN_IDNA_H 37#elif HAVE_IDN_IDNA_H
35#include <idn/idna.h> 38#include <idn/idna.h>
36#endif 39#endif
40#endif
37#if WINDOWS 41#if WINDOWS
38#include <idn-free.h> 42#include <idn-free.h>
39#endif 43#endif
@@ -1084,12 +1088,19 @@ GNUNET_DNSPARSER_builder_add_cert (char *dst,
1084{ 1088{
1085 struct GNUNET_TUN_DnsCertRecord dcert; 1089 struct GNUNET_TUN_DnsCertRecord dcert;
1086 1090
1091#ifdef __clang__
1092#pragma clang diagnostic push
1093#pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare"
1094#endif
1087 if ( (cert->cert_type > UINT16_MAX) || 1095 if ( (cert->cert_type > UINT16_MAX) ||
1088 (cert->algorithm > UINT8_MAX) ) 1096 (cert->algorithm > UINT8_MAX) )
1089 { 1097 {
1090 GNUNET_break (0); 1098 GNUNET_break (0);
1091 return GNUNET_SYSERR; 1099 return GNUNET_SYSERR;
1092 } 1100 }
1101#ifdef __clang__
1102#pragma clang diagnostic pop
1103#endif
1093 if (*off + sizeof (struct GNUNET_TUN_DnsCertRecord) + cert->certificate_size > dst_len) 1104 if (*off + sizeof (struct GNUNET_TUN_DnsCertRecord) + cert->certificate_size > dst_len)
1094 return GNUNET_NO; 1105 return GNUNET_NO;
1095 dcert.cert_type = htons ((uint16_t) cert->cert_type); 1106 dcert.cert_type = htons ((uint16_t) cert->cert_type);
diff --git a/src/util/gnunet-qr.py.in b/src/util/gnunet-qr.py.in
index a5918fdf8..ceed8bd77 100755
--- a/src/util/gnunet-qr.py.in
+++ b/src/util/gnunet-qr.py.in
@@ -1,4 +1,6 @@
1#!@PYTHON@ 1#!@ENV@ python2.7
2from __future__ import print_function
3from builtins import str
2import sys 4import sys
3import getopt 5import getopt
4import subprocess 6import subprocess
@@ -100,7 +102,7 @@ if __name__ == '__main__':
100 cmd += " " + str(a) 102 cmd += " " + str(a)
101 if (verbose): 103 if (verbose):
102 print('Running `' + cmd +'`') 104 print('Running `' + cmd +'`')
103 res=subprocess.call(args) 105 res = subprocess.call(args)
104 if (0 != res): 106 if (0 != res):
105 print('Failed to add URI ' + str(symbol.data)) 107 print('Failed to add URI ' + str(symbol.data))
106 else: 108 else:
diff --git a/src/util/gnunet-service-resolver.c b/src/util/gnunet-service-resolver.c
index d85885d64..0df213588 100644
--- a/src/util/gnunet-service-resolver.c
+++ b/src/util/gnunet-service-resolver.c
@@ -773,6 +773,41 @@ pack (const char *hostname,
773 return GNUNET_OK; 773 return GNUNET_OK;
774} 774}
775 775
776static void
777cache_answers(const char* name,
778 struct GNUNET_DNSPARSER_Record *records,
779 unsigned int num_records)
780{
781 struct ResolveCache *rc;
782 struct GNUNET_DNSPARSER_Record *record;
783 struct RecordListEntry *rle;
784
785 for (unsigned int i = 0; i != num_records; i++)
786 {
787 record = &records[i];
788
789 for (rc = cache_head; NULL != rc; rc = rc->next)
790 if (0 == strcasecmp (rc->hostname,
791 name))
792 break;
793 if (NULL == rc)
794 {
795 rc = GNUNET_new (struct ResolveCache);
796 rc->hostname = GNUNET_strdup (name);
797 GNUNET_CONTAINER_DLL_insert (cache_head,
798 cache_tail,
799 rc);
800 cache_size++;
801 }
802 /* TODO: ought to check first if we have this exact record
803 already in the cache! */
804 rle = GNUNET_new (struct RecordListEntry);
805 rle->record = GNUNET_DNSPARSER_duplicate_record (record);
806 GNUNET_CONTAINER_DLL_insert (rc->records_head,
807 rc->records_tail,
808 rle);
809 }
810}
776 811
777/** 812/**
778 * We got a result from DNS. Add it to the cache and 813 * We got a result from DNS. Add it to the cache and
@@ -784,39 +819,47 @@ pack (const char *hostname,
784 */ 819 */
785static void 820static void
786handle_resolve_result (void *cls, 821handle_resolve_result (void *cls,
787 const struct GNUNET_TUN_DnsHeader *dns, 822 const struct GNUNET_TUN_DnsHeader *dns,
788 size_t dns_len) 823 size_t dns_len)
789{ 824{
790 struct ActiveLookup *al = cls; 825 struct ActiveLookup *al = cls;
791 struct GNUNET_DNSPARSER_Packet *parsed; 826 struct GNUNET_DNSPARSER_Packet *parsed;
792 struct ResolveCache *rc;
793 827
794 parsed = GNUNET_DNSPARSER_parse ((const char *)dns, 828 parsed = GNUNET_DNSPARSER_parse ((const char *)dns,
795 dns_len); 829 dns_len);
796 if (NULL == parsed) 830 if (NULL == parsed)
797 { 831 {
798 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 832 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
799 "Failed to parse DNS reply (hostname %s, request ID %u)\n", 833 "Failed to parse DNS reply (hostname %s, request ID %u)\n",
800 al->hostname, 834 al->hostname,
801 al->dns_id); 835 al->dns_id);
802 return; 836 return;
803 } 837 }
804 if (al->dns_id != ntohs (parsed->id)) 838 if (al->dns_id != ntohs (parsed->id))
805 { 839 {
806 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 840 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
807 "Request ID in DNS reply does not match\n"); 841 "Request ID in DNS reply does not match\n");
808 GNUNET_DNSPARSER_free_packet (parsed); 842 GNUNET_DNSPARSER_free_packet (parsed);
809 return; 843 return;
810 } 844 }
811 if (0 == parsed->num_answers + parsed->num_authority_records + parsed->num_additional_records) 845 if (0 == parsed->num_answers + parsed->num_authority_records + parsed->num_additional_records)
812 { 846 {
813 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 847 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
814 "DNS reply (hostname %s, request ID %u) contains no answers\n", 848 "DNS reply (hostname %s, request ID %u) contains no answers\n",
815 al->hostname, 849 al->hostname,
816 (unsigned int) al->client_request_id); 850 (unsigned int) al->client_request_id);
851 /* resume by trying again from cache */
852 if (GNUNET_NO ==
853 try_cache (al->hostname,
854 al->record_type,
855 al->client_request_id,
856 al->client))
857 /* cache failed, tell client we could not get an answer */
858 {
859 send_end_msg (al->client_request_id,
860 al->client);
861 }
817 GNUNET_DNSPARSER_free_packet (parsed); 862 GNUNET_DNSPARSER_free_packet (parsed);
818 send_end_msg (al->client_request_id,
819 al->client);
820 free_active_lookup (al); 863 free_active_lookup (al);
821 return; 864 return;
822 } 865 }
@@ -829,84 +872,13 @@ handle_resolve_result (void *cls,
829 al->hostname, 872 al->hostname,
830 (unsigned int) al->client_request_id); 873 (unsigned int) al->client_request_id);
831 /* add to cache */ 874 /* add to cache */
832 for (unsigned int i = 0; i != parsed->num_answers; i++) 875 cache_answers(al->hostname,
833 { 876 parsed->answers, parsed->num_answers);
834 struct GNUNET_DNSPARSER_Record *record = &parsed->answers[i]; 877 cache_answers(al->hostname,
835 struct RecordListEntry *rle; 878 parsed->authority_records, parsed->num_authority_records);
836 879 cache_answers(al->hostname,
837 for (rc = cache_head; NULL != rc; rc = rc->next) 880 parsed->additional_records, parsed->num_additional_records);
838 if (0 == strcasecmp (rc->hostname,
839 record->name))
840 break;
841 if (NULL == rc)
842 {
843 rc = GNUNET_new (struct ResolveCache);
844 rc->hostname = GNUNET_strdup (record->name);
845 GNUNET_CONTAINER_DLL_insert (cache_head,
846 cache_tail,
847 rc);
848 cache_size++;
849 }
850 /* TODO: ought to check first if we have this exact record
851 already in the cache! */
852 rle = GNUNET_new (struct RecordListEntry);
853 rle->record = GNUNET_DNSPARSER_duplicate_record (record);
854 GNUNET_CONTAINER_DLL_insert (rc->records_head,
855 rc->records_tail,
856 rle);
857 }
858 for (unsigned int i = 0; i != parsed->num_authority_records; i++)
859 {
860 struct GNUNET_DNSPARSER_Record *record = &parsed->authority_records[i];
861 struct RecordListEntry *rle;
862
863 for (rc = cache_head; NULL != rc; rc = rc->next)
864 if (0 == strcasecmp (rc->hostname,
865 record->name))
866 break;
867 if (NULL == rc)
868 {
869 rc = GNUNET_new (struct ResolveCache);
870 rc->hostname = GNUNET_strdup (record->name);
871 GNUNET_CONTAINER_DLL_insert (cache_head,
872 cache_tail,
873 rc);
874 cache_size++;
875 }
876 /* TODO: ought to check first if we have this exact record
877 already in the cache! */
878 rle = GNUNET_new (struct RecordListEntry);
879 rle->record = GNUNET_DNSPARSER_duplicate_record (record);
880 GNUNET_CONTAINER_DLL_insert (rc->records_head,
881 rc->records_tail,
882 rle);
883 }
884 for (unsigned int i = 0; i != parsed->num_additional_records; i++)
885 {
886 struct GNUNET_DNSPARSER_Record *record = &parsed->additional_records[i];
887 struct RecordListEntry *rle;
888 881
889 for (rc = cache_head; NULL != rc; rc = rc->next)
890 if (0 == strcasecmp (rc->hostname,
891 record->name))
892 break;
893 if (NULL == rc)
894 {
895 rc = GNUNET_new (struct ResolveCache);
896 rc->hostname = GNUNET_strdup (record->name);
897 GNUNET_CONTAINER_DLL_insert (cache_head,
898 cache_tail,
899 rc);
900 cache_size++;
901 }
902 /* TODO: ought to check first if we have this exact record
903 already in the cache! */
904 rle = GNUNET_new (struct RecordListEntry);
905 rle->record = GNUNET_DNSPARSER_duplicate_record (record);
906 GNUNET_CONTAINER_DLL_insert (rc->records_head,
907 rc->records_tail,
908 rle);
909 }
910 /* see if we need to do the 2nd request for AAAA records */ 882 /* see if we need to do the 2nd request for AAAA records */
911 if ( (GNUNET_DNSPARSER_TYPE_ALL == al->record_type) && 883 if ( (GNUNET_DNSPARSER_TYPE_ALL == al->record_type) &&
912 (GNUNET_NO == al->did_aaaa) ) 884 (GNUNET_NO == al->did_aaaa) )
@@ -968,7 +940,7 @@ handle_resolve_timeout (void *cls)
968 940
969 al->timeout_task = NULL; 941 al->timeout_task = NULL;
970 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 942 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
971 "DNS lookup timeout!\n"); 943 "DNS lookup timeout!\n");
972 send_end_msg (al->client_request_id, 944 send_end_msg (al->client_request_id,
973 al->client); 945 al->client);
974 free_active_lookup (al); 946 free_active_lookup (al);
@@ -987,9 +959,9 @@ handle_resolve_timeout (void *cls)
987 */ 959 */
988static int 960static int
989resolve_and_cache (const char* hostname, 961resolve_and_cache (const char* hostname,
990 uint16_t record_type, 962 uint16_t record_type,
991 uint32_t client_request_id, 963 uint32_t client_request_id,
992 struct GNUNET_SERVICE_Client *client) 964 struct GNUNET_SERVICE_Client *client)
993{ 965{
994 char *packet_buf; 966 char *packet_buf;
995 size_t packet_size; 967 size_t packet_size;
@@ -998,8 +970,8 @@ resolve_and_cache (const char* hostname,
998 uint16_t type; 970 uint16_t type;
999 971
1000 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 972 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1001 "resolve_and_cache `%s'\n", 973 "resolve_and_cache `%s'\n",
1002 hostname); 974 hostname);
1003 dns_id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, 975 dns_id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1004 UINT16_MAX); 976 UINT16_MAX);
1005 977
@@ -1015,7 +987,7 @@ resolve_and_cache (const char* hostname,
1015 &packet_size)) 987 &packet_size))
1016 { 988 {
1017 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 989 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1018 "Failed to pack query for hostname `%s'\n", 990 "Failed to pack query for hostname `%s'\n",
1019 hostname); 991 hostname);
1020 return GNUNET_SYSERR; 992 return GNUNET_SYSERR;
1021 } 993 }
@@ -1031,19 +1003,19 @@ resolve_and_cache (const char* hostname,
1031 al); 1003 al);
1032 al->resolve_handle = 1004 al->resolve_handle =
1033 GNUNET_DNSSTUB_resolve (dnsstub_ctx, 1005 GNUNET_DNSSTUB_resolve (dnsstub_ctx,
1034 packet_buf, 1006 packet_buf,
1035 packet_size, 1007 packet_size,
1036 &handle_resolve_result, 1008 &handle_resolve_result,
1037 al); 1009 al);
1038 GNUNET_free (packet_buf); 1010 GNUNET_free (packet_buf);
1039 GNUNET_CONTAINER_DLL_insert (lookup_head, 1011 GNUNET_CONTAINER_DLL_insert (lookup_head,
1040 lookup_tail, 1012 lookup_tail,
1041 al); 1013 al);
1042 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1014 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1043 "Resolving %s, client_request_id = %u, dns_id = %u\n", 1015 "Resolving %s, client_request_id = %u, dns_id = %u\n",
1044 hostname, 1016 hostname,
1045 (unsigned int) client_request_id, 1017 (unsigned int) client_request_id,
1046 (unsigned int) dns_id); 1018 (unsigned int) dns_id);
1047 return GNUNET_OK; 1019 return GNUNET_OK;
1048} 1020}
1049 1021
@@ -1059,29 +1031,29 @@ resolve_and_cache (const char* hostname,
1059 */ 1031 */
1060static void 1032static void
1061process_get (const char *hostname, 1033process_get (const char *hostname,
1062 uint16_t record_type, 1034 uint16_t record_type,
1063 uint32_t client_request_id, 1035 uint32_t client_request_id,
1064 struct GNUNET_SERVICE_Client *client) 1036 struct GNUNET_SERVICE_Client *client)
1065{ 1037{
1066 char fqdn[255]; 1038 char fqdn[255];
1067 1039
1068 if ( (NULL != my_domain) && 1040 if ( (NULL != my_domain) &&
1069 (NULL == strchr (hostname, 1041 (NULL == strchr (hostname,
1070 (unsigned char) '.')) && 1042 (unsigned char) '.')) &&
1071 (strlen (hostname) + strlen (my_domain) <= 253) ) 1043 (strlen (hostname) + strlen (my_domain) <= 253) )
1072 { 1044 {
1073 GNUNET_snprintf (fqdn, 1045 GNUNET_snprintf (fqdn,
1074 sizeof (fqdn), 1046 sizeof (fqdn),
1075 "%s.%s", 1047 "%s.%s",
1076 hostname, 1048 hostname,
1077 my_domain); 1049 my_domain);
1078 } 1050 }
1079 else if (strlen (hostname) < 255) 1051 else if (strlen (hostname) < 255)
1080 { 1052 {
1081 GNUNET_snprintf (fqdn, 1053 GNUNET_snprintf (fqdn,
1082 sizeof (fqdn), 1054 sizeof (fqdn),
1083 "%s", 1055 "%s",
1084 hostname); 1056 hostname);
1085 } 1057 }
1086 else 1058 else
1087 { 1059 {
@@ -1117,7 +1089,7 @@ process_get (const char *hostname,
1117 */ 1089 */
1118static int 1090static int
1119check_get (void *cls, 1091check_get (void *cls,
1120 const struct GNUNET_RESOLVER_GetMessage *get) 1092 const struct GNUNET_RESOLVER_GetMessage *get)
1121{ 1093{
1122 uint16_t size; 1094 uint16_t size;
1123 int direction; 1095 int direction;
@@ -1134,23 +1106,23 @@ check_get (void *cls,
1134 af = ntohl (get->af); 1106 af = ntohl (get->af);
1135 switch (af) 1107 switch (af)
1136 { 1108 {
1137 case AF_INET: 1109 case AF_INET:
1138 if (size != sizeof (struct in_addr)) 1110 if (size != sizeof (struct in_addr))
1139 { 1111 {
1140 GNUNET_break (0); 1112 GNUNET_break (0);
1141 return GNUNET_SYSERR; 1113 return GNUNET_SYSERR;
1142 } 1114 }
1143 break; 1115 break;
1144 case AF_INET6: 1116 case AF_INET6:
1145 if (size != sizeof (struct in6_addr)) 1117 if (size != sizeof (struct in6_addr))
1146 { 1118 {
1119 GNUNET_break (0);
1120 return GNUNET_SYSERR;
1121 }
1122 break;
1123 default:
1147 GNUNET_break (0); 1124 GNUNET_break (0);
1148 return GNUNET_SYSERR; 1125 return GNUNET_SYSERR;
1149 }
1150 break;
1151 default:
1152 GNUNET_break (0);
1153 return GNUNET_SYSERR;
1154 } 1126 }
1155 return GNUNET_OK; 1127 return GNUNET_OK;
1156} 1128}
@@ -1164,7 +1136,7 @@ check_get (void *cls,
1164 */ 1136 */
1165static void 1137static void
1166handle_get (void *cls, 1138handle_get (void *cls,
1167 const struct GNUNET_RESOLVER_GetMessage *msg) 1139 const struct GNUNET_RESOLVER_GetMessage *msg)
1168{ 1140{
1169 struct GNUNET_SERVICE_Client *client = cls; 1141 struct GNUNET_SERVICE_Client *client = cls;
1170 int direction; 1142 int direction;
@@ -1183,36 +1155,36 @@ handle_get (void *cls,
1183 switch (af) 1155 switch (af)
1184 { 1156 {
1185 case AF_UNSPEC: 1157 case AF_UNSPEC:
1186 { 1158 {
1187 process_get (hostname, 1159 process_get (hostname,
1188 GNUNET_DNSPARSER_TYPE_ALL, 1160 GNUNET_DNSPARSER_TYPE_ALL,
1189 client_request_id, 1161 client_request_id,
1190 client); 1162 client);
1191 break; 1163 break;
1192 } 1164 }
1193 case AF_INET: 1165 case AF_INET:
1194 { 1166 {
1195 process_get (hostname, 1167 process_get (hostname,
1196 GNUNET_DNSPARSER_TYPE_A, 1168 GNUNET_DNSPARSER_TYPE_A,
1197 client_request_id, 1169 client_request_id,
1198 client); 1170 client);
1199 break; 1171 break;
1200 } 1172 }
1201 case AF_INET6: 1173 case AF_INET6:
1202 { 1174 {
1203 process_get (hostname, 1175 process_get (hostname,
1204 GNUNET_DNSPARSER_TYPE_AAAA, 1176 GNUNET_DNSPARSER_TYPE_AAAA,
1205 client_request_id, 1177 client_request_id,
1206 client); 1178 client);
1207 break; 1179 break;
1208 } 1180 }
1209 default: 1181 default:
1210 { 1182 {
1211 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1183 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1212 "got invalid af: %d\n", 1184 "got invalid af: %d\n",
1213 af); 1185 af);
1214 GNUNET_assert (0); 1186 GNUNET_assert (0);
1215 } 1187 }
1216 } 1188 }
1217 } 1189 }
1218 else 1190 else
@@ -1246,7 +1218,7 @@ shutdown_task (void *cls)
1246 while (NULL != hosts_head) 1218 while (NULL != hosts_head)
1247 free_hosts_entry (hosts_head); 1219 free_hosts_entry (hosts_head);
1248 GNUNET_DNSSTUB_stop (dnsstub_ctx); 1220 GNUNET_DNSSTUB_stop (dnsstub_ctx);
1249 GNUNET_free (my_domain); 1221 GNUNET_free_non_null (my_domain);
1250} 1222}
1251 1223
1252 1224
@@ -1261,9 +1233,9 @@ shutdown_task (void *cls)
1261 */ 1233 */
1262static void 1234static void
1263add_host (const char *hostname, 1235add_host (const char *hostname,
1264 uint16_t rec_type, 1236 uint16_t rec_type,
1265 const void *data, 1237 const void *data,
1266 size_t data_size) 1238 size_t data_size)
1267{ 1239{
1268 struct ResolveCache *rc; 1240 struct ResolveCache *rc;
1269 struct RecordListEntry *rle; 1241 struct RecordListEntry *rle;
@@ -1275,18 +1247,18 @@ add_host (const char *hostname,
1275 rec->dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET; 1247 rec->dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
1276 rec->name = GNUNET_strdup (hostname); 1248 rec->name = GNUNET_strdup (hostname);
1277 rec->data.raw.data = GNUNET_memdup (data, 1249 rec->data.raw.data = GNUNET_memdup (data,
1278 data_size); 1250 data_size);
1279 rec->data.raw.data_len = data_size; 1251 rec->data.raw.data_len = data_size;
1280 rle = GNUNET_new (struct RecordListEntry); 1252 rle = GNUNET_new (struct RecordListEntry);
1281 rle->record = rec; 1253 rle->record = rec;
1282 rc = GNUNET_new (struct ResolveCache); 1254 rc = GNUNET_new (struct ResolveCache);
1283 rc->hostname = GNUNET_strdup (hostname); 1255 rc->hostname = GNUNET_strdup (hostname);
1284 GNUNET_CONTAINER_DLL_insert (rc->records_head, 1256 GNUNET_CONTAINER_DLL_insert (rc->records_head,
1285 rc->records_tail, 1257 rc->records_tail,
1286 rle); 1258 rle);
1287 GNUNET_CONTAINER_DLL_insert (hosts_head, 1259 GNUNET_CONTAINER_DLL_insert (hosts_head,
1288 hosts_tail, 1260 hosts_tail,
1289 rc); 1261 rc);
1290} 1262}
1291 1263
1292 1264
@@ -1298,7 +1270,7 @@ add_host (const char *hostname,
1298 */ 1270 */
1299static void 1271static void
1300extract_hosts (const char *line, 1272extract_hosts (const char *line,
1301 size_t line_len) 1273 size_t line_len)
1302{ 1274{
1303 const char *c; 1275 const char *c;
1304 struct in_addr v4; 1276 struct in_addr v4;
@@ -1308,19 +1280,19 @@ extract_hosts (const char *line,
1308 1280
1309 /* ignore everything after '#' */ 1281 /* ignore everything after '#' */
1310 c = memrchr (line, 1282 c = memrchr (line,
1311 (unsigned char) '#', 1283 (unsigned char) '#',
1312 line_len); 1284 line_len);
1313 if (NULL != c) 1285 if (NULL != c)
1314 line_len = c - line; 1286 line_len = c - line;
1315 /* ignore leading whitespace */ 1287 /* ignore leading whitespace */
1316 while ( (0 < line_len) && 1288 while ( (0 < line_len) &&
1317 isspace ((unsigned char) *line) ) 1289 isspace ((unsigned char) *line) )
1318 { 1290 {
1319 line++; 1291 line++;
1320 line_len--; 1292 line_len--;
1321 } 1293 }
1322 tbuf = GNUNET_strndup (line, 1294 tbuf = GNUNET_strndup (line,
1323 line_len); 1295 line_len);
1324 tok = strtok (tbuf, " \t"); 1296 tok = strtok (tbuf, " \t");
1325 if (NULL == tok) 1297 if (NULL == tok)
1326 { 1298 {
@@ -1328,24 +1300,24 @@ extract_hosts (const char *line,
1328 return; 1300 return;
1329 } 1301 }
1330 if (1 == inet_pton (AF_INET, 1302 if (1 == inet_pton (AF_INET,
1331 tok, 1303 tok,
1332 &v4)) 1304 &v4))
1333 { 1305 {
1334 while (NULL != (tok = strtok (NULL, " \t"))) 1306 while (NULL != (tok = strtok (NULL, " \t")))
1335 add_host (tok, 1307 add_host (tok,
1336 GNUNET_DNSPARSER_TYPE_A, 1308 GNUNET_DNSPARSER_TYPE_A,
1337 &v4, 1309 &v4,
1338 sizeof (struct in_addr)); 1310 sizeof (struct in_addr));
1339 } 1311 }
1340 else if (1 == inet_pton (AF_INET6, 1312 else if (1 == inet_pton (AF_INET6,
1341 tok, 1313 tok,
1342 &v6)) 1314 &v6))
1343 { 1315 {
1344 while (NULL != (tok = strtok (NULL, " \t"))) 1316 while (NULL != (tok = strtok (NULL, " \t")))
1345 add_host (tok, 1317 add_host (tok,
1346 GNUNET_DNSPARSER_TYPE_AAAA, 1318 GNUNET_DNSPARSER_TYPE_AAAA,
1347 &v6, 1319 &v6,
1348 sizeof (struct in6_addr)); 1320 sizeof (struct in6_addr));
1349 } 1321 }
1350 GNUNET_free (tbuf); 1322 GNUNET_free (tbuf);
1351} 1323}
@@ -1364,36 +1336,36 @@ load_etc_hosts (void)
1364 size_t read_offset; 1336 size_t read_offset;
1365 1337
1366 fh = GNUNET_DISK_file_open ("/etc/hosts", 1338 fh = GNUNET_DISK_file_open ("/etc/hosts",
1367 GNUNET_DISK_OPEN_READ, 1339 GNUNET_DISK_OPEN_READ,
1368 GNUNET_DISK_PERM_NONE); 1340 GNUNET_DISK_PERM_NONE);
1369 if (NULL == fh) 1341 if (NULL == fh)
1370 { 1342 {
1371 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1343 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1372 "Failed to open /etc/hosts"); 1344 "Failed to open /etc/hosts");
1373 return; 1345 return;
1374 } 1346 }
1375 if (GNUNET_OK != 1347 if (GNUNET_OK !=
1376 GNUNET_DISK_file_handle_size (fh, 1348 GNUNET_DISK_file_handle_size (fh,
1377 &bytes_read)) 1349 &bytes_read))
1378 { 1350 {
1379 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1351 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1380 "Could not determin size of /etc/hosts. " 1352 "Could not determin size of /etc/hosts. "
1381 "DNS resolution will not be possible.\n"); 1353 "DNS resolution will not be possible.\n");
1382 GNUNET_DISK_file_close (fh); 1354 GNUNET_DISK_file_close (fh);
1383 return; 1355 return;
1384 } 1356 }
1385 if ((size_t) bytes_read > SIZE_MAX) 1357 if ((size_t) bytes_read > SIZE_MAX)
1386 { 1358 {
1387 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1359 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1388 "/etc/hosts file too large to mmap. " 1360 "/etc/hosts file too large to mmap. "
1389 "DNS resolution will not be possible.\n"); 1361 "DNS resolution will not be possible.\n");
1390 GNUNET_DISK_file_close (fh); 1362 GNUNET_DISK_file_close (fh);
1391 return; 1363 return;
1392 } 1364 }
1393 buf = GNUNET_DISK_file_map (fh, 1365 buf = GNUNET_DISK_file_map (fh,
1394 &mh, 1366 &mh,
1395 GNUNET_DISK_MAP_TYPE_READ, 1367 GNUNET_DISK_MAP_TYPE_READ,
1396 (size_t) bytes_read); 1368 (size_t) bytes_read);
1397 read_offset = 0; 1369 read_offset = 0;
1398 while (read_offset < (size_t) bytes_read) 1370 while (read_offset < (size_t) bytes_read)
1399 { 1371 {
@@ -1406,7 +1378,7 @@ load_etc_hosts (void)
1406 break; 1378 break;
1407 line_len = newline - buf - read_offset; 1379 line_len = newline - buf - read_offset;
1408 extract_hosts (buf + read_offset, 1380 extract_hosts (buf + read_offset,
1409 line_len); 1381 line_len);
1410 read_offset += line_len + 1; 1382 read_offset += line_len + 1;
1411 } 1383 }
1412 GNUNET_DISK_file_unmap (mh); 1384 GNUNET_DISK_file_unmap (mh);
@@ -1423,8 +1395,8 @@ load_etc_hosts (void)
1423 */ 1395 */
1424static void 1396static void
1425init_cb (void *cls, 1397init_cb (void *cls,
1426 const struct GNUNET_CONFIGURATION_Handle *cfg, 1398 const struct GNUNET_CONFIGURATION_Handle *cfg,
1427 struct GNUNET_SERVICE_Handle *sh) 1399 struct GNUNET_SERVICE_Handle *sh)
1428{ 1400{
1429 char **dns_servers; 1401 char **dns_servers;
1430 int num_dns_servers; 1402 int num_dns_servers;
@@ -1433,23 +1405,23 @@ init_cb (void *cls,
1433 (void) sh; 1405 (void) sh;
1434 load_etc_hosts (); 1406 load_etc_hosts ();
1435 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 1407 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1436 cls); 1408 cls);
1437 dnsstub_ctx = GNUNET_DNSSTUB_start (128); 1409 dnsstub_ctx = GNUNET_DNSSTUB_start (128);
1438 dns_servers = NULL; 1410 dns_servers = NULL;
1439 num_dns_servers = lookup_dns_servers (&dns_servers); 1411 num_dns_servers = lookup_dns_servers (&dns_servers);
1440 if (0 >= num_dns_servers) 1412 if (0 >= num_dns_servers)
1441 { 1413 {
1442 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1414 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1443 _("No DNS server available. DNS resolution will not be possible.\n")); 1415 _("No DNS server available. DNS resolution will not be possible.\n"));
1444 return; 1416 return;
1445 } 1417 }
1446 for (int i = 0; i < num_dns_servers; i++) 1418 for (int i = 0; i < num_dns_servers; i++)
1447 { 1419 {
1448 int result = GNUNET_DNSSTUB_add_dns_ip (dnsstub_ctx, dns_servers[i]); 1420 int result = GNUNET_DNSSTUB_add_dns_ip (dnsstub_ctx, dns_servers[i]);
1449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1421 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1450 "Adding DNS server '%s': %s\n", 1422 "Adding DNS server '%s': %s\n",
1451 dns_servers[i], 1423 dns_servers[i],
1452 GNUNET_OK == result ? "success" : "failure"); 1424 GNUNET_OK == result ? "success" : "failure");
1453 GNUNET_free (dns_servers[i]); 1425 GNUNET_free (dns_servers[i]);
1454 } 1426 }
1455 GNUNET_free_non_null (dns_servers); 1427 GNUNET_free_non_null (dns_servers);
@@ -1466,8 +1438,8 @@ init_cb (void *cls,
1466 */ 1438 */
1467static void * 1439static void *
1468connect_cb (void *cls, 1440connect_cb (void *cls,
1469 struct GNUNET_SERVICE_Client *c, 1441 struct GNUNET_SERVICE_Client *c,
1470 struct GNUNET_MQ_Handle *mq) 1442 struct GNUNET_MQ_Handle *mq)
1471{ 1443{
1472 (void) cls; 1444 (void) cls;
1473 (void) mq; 1445 (void) mq;
@@ -1485,8 +1457,8 @@ connect_cb (void *cls,
1485 */ 1457 */
1486static void 1458static void
1487disconnect_cb (void *cls, 1459disconnect_cb (void *cls,
1488 struct GNUNET_SERVICE_Client *c, 1460 struct GNUNET_SERVICE_Client *c,
1489 void *internal_cls) 1461 void *internal_cls)
1490{ 1462{
1491 struct ActiveLookup *n; 1463 struct ActiveLookup *n;
1492 (void) cls; 1464 (void) cls;
@@ -1515,9 +1487,9 @@ GNUNET_SERVICE_MAIN
1515 &disconnect_cb, 1487 &disconnect_cb,
1516 NULL, 1488 NULL,
1517 GNUNET_MQ_hd_var_size (get, 1489 GNUNET_MQ_hd_var_size (get,
1518 GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST, 1490 GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST,
1519 struct GNUNET_RESOLVER_GetMessage, 1491 struct GNUNET_RESOLVER_GetMessage,
1520 NULL), 1492 NULL),
1521 GNUNET_MQ_handler_end ()); 1493 GNUNET_MQ_handler_end ());
1522 1494
1523 1495
diff --git a/src/util/mq.c b/src/util/mq.c
index d2f5add19..72ab8b72d 100644
--- a/src/util/mq.c
+++ b/src/util/mq.c
@@ -964,6 +964,7 @@ GNUNET_MQ_send_cancel (struct GNUNET_MQ_Envelope *ev)
964 { 964 {
965 /* complex case, we already started with transmitting 965 /* complex case, we already started with transmitting
966 the message using the callbacks. */ 966 the message using the callbacks. */
967 GNUNET_assert (GNUNET_NO == mq->in_flight);
967 GNUNET_assert (0 < mq->queue_length); 968 GNUNET_assert (0 < mq->queue_length);
968 mq->queue_length--; 969 mq->queue_length--;
969 mq->cancel_impl (mq, 970 mq->cancel_impl (mq,
diff --git a/src/util/scheduler.c b/src/util/scheduler.c
index dd0d5d5cf..3bd7ccec7 100644
--- a/src/util/scheduler.c
+++ b/src/util/scheduler.c
@@ -658,8 +658,8 @@ sighandler_shutdown ()
658 int old_errno = errno; /* backup errno */ 658 int old_errno = errno; /* backup errno */
659 659
660 if (getpid () != my_pid) 660 if (getpid () != my_pid)
661 exit (1); /* we have fork'ed since the signal handler was created, 661 _exit (1); /* we have fork'ed since the signal handler was created,
662 * ignore the signal, see https://gnunet.org/vfork discussion */ 662 * ignore the signal, see https://gnunet.org/vfork discussion */
663 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle 663 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
664 (shutdown_pipe_handle, GNUNET_DISK_PIPE_END_WRITE), 664 (shutdown_pipe_handle, GNUNET_DISK_PIPE_END_WRITE),
665 &c, sizeof (c)); 665 &c, sizeof (c));
diff --git a/src/util/service.c b/src/util/service.c
index 5117f006f..f38e4b353 100644
--- a/src/util/service.c
+++ b/src/util/service.c
@@ -888,6 +888,8 @@ accept_client (void *cls)
888 start_client (slc->sh, 888 start_client (slc->sh,
889 sock); 889 sock);
890 } 890 }
891 if (0 != sh->suspend_state)
892 return;
891 slc->listen_task 893 slc->listen_task
892 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, 894 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
893 slc->listen_socket, 895 slc->listen_socket,