X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fconversation%2Ftest_conversation_api.c;h=a80f5dc0c42b980cb0312561b44f099623d57a9a;hb=80d2de6cdc4d253c7fbc6a4bc067d856aab9cca9;hp=7860eb794887e91a30ddb33e0a58bf1a4f920e70;hpb=2b9080ac724c387cdc7197d1b476e138cdc280dd;p=oweals%2Fgnunet.git diff --git a/src/conversation/test_conversation_api.c b/src/conversation/test_conversation_api.c index 7860eb794..a80f5dc0c 100644 --- a/src/conversation/test_conversation_api.c +++ b/src/conversation/test_conversation_api.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) + Copyright (C) 2013, 2014 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -14,72 +14,494 @@ You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ /** - * @file src/test_conversation_api.c + * @file conversation/test_conversation_api.c * @brief testcase for conversation_api.c + * + * This test performs the operations of a call to a phone + * where the phone user picks up and then the call is + * terminated by the party that initiated the call. */ -#include -#include +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_testing_lib.h" +#include "gnunet_gnsrecord_lib.h" #include "gnunet_conversation_service.h" +#include "gnunet_identity_service.h" +#include "gnunet_namestore_service.h" +#define FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250) + +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 25) static int ok = 1; +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +static struct GNUNET_IDENTITY_Handle *id; + +static struct GNUNET_IDENTITY_Operation *op; + +static struct GNUNET_CONVERSATION_Phone *phone; + +static struct GNUNET_NAMESTORE_Handle *ns; + +static struct GNUNET_CONVERSATION_Call *call; + +static struct GNUNET_NAMESTORE_QueueEntry *qe; + +static struct GNUNET_CONVERSATION_Caller *active_caller; + +static char *gns_name; + +static char *gns_caller_id; + +static GNUNET_MICROPHONE_RecordedDataCallback phone_rdc; + +static void *phone_rdc_cls; + +static GNUNET_MICROPHONE_RecordedDataCallback call_rdc; + +static void *call_rdc_cls; + +static struct GNUNET_SCHEDULER_Task * phone_task; + +static struct GNUNET_SCHEDULER_Task * call_task; + static void -run (void *cls, - char *const *args, - const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) +phone_send (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + static unsigned int i; + char buf[32]; + + GNUNET_assert (NULL != phone_rdc); + GNUNET_snprintf (buf, sizeof (buf), "phone-%u", i++); + phone_rdc (phone_rdc_cls, strlen (buf) + 1, buf); + phone_task = GNUNET_SCHEDULER_add_delayed (FREQ, + &phone_send, NULL); +} + + +static void +call_send (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) { - ok = 0; + static unsigned int i; + char buf[32]; + + GNUNET_assert (NULL != call_rdc); + GNUNET_snprintf (buf, sizeof (buf), "call-%u", i++); + call_rdc (call_rdc_cls, strlen (buf) + 1, buf); + call_task = GNUNET_SCHEDULER_add_delayed (FREQ, + &call_send, NULL); } static int -check () -{ - char *const argv[] = { "test-conversation-api", NULL }; - struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_OPTION_END - }; - struct GNUNET_OS_Process *proc; - char *path = GNUNET_OS_get_libexec_binary_path ( "gnunet-service-conversation"); - if (NULL == path) - { - fprintf (stderr, "Service executable not found `%s'\n", "gnunet-service-conversation"); - return; - } - proc = GNUNET_OS_start_process (GNUNET_NO, GNUNET_OS_INHERIT_STD_ALL, NULL, NULL, - path, - "gnunet-service-conversation", - NULL); - - GNUNET_free (path); - GNUNET_assert (NULL != proc); - GNUNET_PROGRAM_run (1, argv, "test-ext-conversation", "nohelp", - options, &run, &ok); - if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); - ok = 1; - } - GNUNET_OS_process_wait (proc); - GNUNET_OS_process_destroy (proc); - return ok; +enable_speaker (void *cls) +{ + const char *origin = cls; + + fprintf (stderr, + "Speaker %s enabled\n", + origin); + return GNUNET_OK; +} + + +static void +disable_speaker (void *cls) +{ + const char *origin = cls; + + fprintf (stderr, + "Speaker %s disabled\n", + origin); +} + + +static void +play (void *cls, + size_t data_size, + const void *data) +{ + const char *origin = cls; + static unsigned int phone_i = 1; + static unsigned int call_i; + char buf[32]; + + if (0 == strcmp (origin, "phone")) + GNUNET_snprintf (buf, sizeof (buf), "call-%u", call_i++); + else + GNUNET_snprintf (buf, sizeof (buf), "phone-%u", phone_i++); + if ( (data_size != strlen (buf) + 1) || + (0 != strncmp (buf, data, data_size)) ) + { + fprintf (stderr, + "Expected %s, received %.*s\n", + buf, + (int) data_size, + (const char *) data); + } + else + { + fprintf (stderr, "."); + } + if ( (20 < call_i) && + (20 < phone_i) && + (NULL != call) ) + { + /* time to hang up ... */ + GNUNET_CONVERSATION_call_stop (call); + call = NULL; + } +} + + +static void +destroy_speaker (void *cls) +{ + const char *origin = cls; + + fprintf (stderr, "Speaker %s destroyed\n", origin); +} + + +static struct GNUNET_SPEAKER_Handle call_speaker = { + &enable_speaker, + &play, + &disable_speaker, + &destroy_speaker, + "caller" +}; + + +static struct GNUNET_SPEAKER_Handle phone_speaker = { + &enable_speaker, + &play, + &disable_speaker, + &destroy_speaker, + "phone" +}; + + +static int +enable_mic (void *cls, + GNUNET_MICROPHONE_RecordedDataCallback rdc, + void *rdc_cls) +{ + const char *origin = cls; + + fprintf (stderr, + "Mic %s enabled\n", + origin); + if (0 == strcmp (origin, "phone")) + { + phone_rdc = rdc; + phone_rdc_cls = rdc_cls; + phone_task = GNUNET_SCHEDULER_add_now (&phone_send, NULL); + } + else + { + call_rdc = rdc; + call_rdc_cls = rdc_cls; + call_task = GNUNET_SCHEDULER_add_now (&call_send, NULL); + } + return GNUNET_OK; +} + + +static void +disable_mic (void *cls) +{ + const char *origin = cls; + + fprintf (stderr, + "Mic %s disabled\n", + origin); + if (0 == strcmp (origin, "phone")) + { + phone_rdc = NULL; + phone_rdc_cls = NULL; + GNUNET_SCHEDULER_cancel (phone_task); + phone_task = NULL; + } + else + { + call_rdc = NULL; + call_rdc_cls = NULL; + GNUNET_SCHEDULER_cancel (call_task); + call_task = NULL; + } +} + + +static void +destroy_mic (void *cls) +{ + const char *origin = cls; + + fprintf (stderr, + "Mic %s destroyed\n", + origin); +} + + +static struct GNUNET_MICROPHONE_Handle call_mic = { + &enable_mic, + &disable_mic, + &destroy_mic, + "caller" +}; + + +static struct GNUNET_MICROPHONE_Handle phone_mic = { + &enable_mic, + &disable_mic, + &destroy_mic, + "phone" +}; + + +/** + * Signature of the main function of a task. + * + * @param cls closure + * @param tc context information (why was this task triggered now) + */ +static void +end_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_SCHEDULER_shutdown (); + if (NULL != op) + { + GNUNET_IDENTITY_cancel (op); + op = NULL; + } + if (NULL != call) + { + GNUNET_CONVERSATION_call_stop (call); + call = NULL; + } + if (NULL != phone) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from PHONE service.\n"); + GNUNET_CONVERSATION_phone_destroy (phone); + phone = NULL; + } + if (NULL != id) + { + GNUNET_IDENTITY_disconnect (id); + id = NULL; + } + if (NULL != qe) + { + GNUNET_NAMESTORE_cancel (qe); + qe = NULL; + } + if (NULL != ns) + { + GNUNET_NAMESTORE_disconnect (ns); + ns = NULL; + } +} + + +static void +caller_event_handler (void *cls, + enum GNUNET_CONVERSATION_CallerEventCode code) +{ + switch (code) + { + case GNUNET_CONVERSATION_EC_CALLER_SUSPEND: + case GNUNET_CONVERSATION_EC_CALLER_RESUME: + fprintf (stderr, "Unexpected caller code: %d\n", code); + break; + } +} + + +static void +phone_event_handler (void *cls, + enum GNUNET_CONVERSATION_PhoneEventCode code, + struct GNUNET_CONVERSATION_Caller *caller, + const struct GNUNET_CRYPTO_EcdsaPublicKey *caller_id) +{ + static enum GNUNET_CONVERSATION_PhoneEventCode expect + = GNUNET_CONVERSATION_EC_PHONE_RING; + + GNUNET_break (code == expect); + switch (code) + { + case GNUNET_CONVERSATION_EC_PHONE_RING: + active_caller = caller; + GNUNET_CONVERSATION_caller_pick_up (caller, + &caller_event_handler, + NULL, + &phone_speaker, + &phone_mic); + expect = GNUNET_CONVERSATION_EC_PHONE_HUNG_UP; + break; + case GNUNET_CONVERSATION_EC_PHONE_HUNG_UP: + GNUNET_break (caller == active_caller); + active_caller = NULL; + ok = 0; + GNUNET_SCHEDULER_shutdown (); + break; + default: + fprintf (stderr, "Unexpected phone code: %d\n", code); + break; + } +} + + +static void +call_event_handler (void *cls, + enum GNUNET_CONVERSATION_CallEventCode code) +{ + static enum GNUNET_CONVERSATION_CallEventCode expect + = GNUNET_CONVERSATION_EC_CALL_RINGING; + + GNUNET_break (code == expect); + switch (code) + { + case GNUNET_CONVERSATION_EC_CALL_RINGING: + expect = GNUNET_CONVERSATION_EC_CALL_PICKED_UP; + break; + case GNUNET_CONVERSATION_EC_CALL_PICKED_UP: + expect = -1; + break; + case GNUNET_CONVERSATION_EC_CALL_GNS_FAIL: + case GNUNET_CONVERSATION_EC_CALL_HUNG_UP: + call = NULL; + fprintf (stderr, "Unexpected call code: %d\n", code); + break; + case GNUNET_CONVERSATION_EC_CALL_SUSPENDED: + case GNUNET_CONVERSATION_EC_CALL_RESUMED: + case GNUNET_CONVERSATION_EC_CALL_ERROR: + fprintf (stderr, "Unexpected call code: %d\n", code); + break; + } +} + + +static void +caller_ego_create_cont (void *cls, + const char *emsg) +{ + op = NULL; + GNUNET_assert (NULL == emsg); +} + + +static void +namestore_put_cont (void *cls, + int32_t success, + const char *emsg) +{ + qe = NULL; + GNUNET_assert (GNUNET_YES == success); + GNUNET_assert (NULL == emsg); + GNUNET_assert (NULL == op); + op = GNUNET_IDENTITY_create (id, "caller-ego", &caller_ego_create_cont, NULL); +} + + +static void +identity_cb (void *cls, + struct GNUNET_IDENTITY_Ego *ego, + void **ctx, + const char *name) +{ + struct GNUNET_GNSRECORD_Data rd; + struct GNUNET_CRYPTO_EcdsaPublicKey pub; + + if (NULL == name) + return; + if (NULL == ego) + return; + if (0 == strcmp (name, "phone-ego")) + { + GNUNET_IDENTITY_ego_get_public_key (ego, &pub); + GNUNET_asprintf (&gns_name, + "phone.%s", + GNUNET_GNSRECORD_pkey_to_zkey (&pub)); + phone = GNUNET_CONVERSATION_phone_create (cfg, + ego, + &phone_event_handler, + NULL); + GNUNET_assert (NULL != phone); + memset (&rd, 0, sizeof (rd)); + GNUNET_CONVERSATION_phone_get_record (phone, + &rd); + GNUNET_assert (rd.record_type == GNUNET_GNSRECORD_TYPE_PHONE); + rd.expiration_time = UINT64_MAX; + qe = GNUNET_NAMESTORE_records_store (ns, + GNUNET_IDENTITY_ego_get_private_key (ego), + "phone" /* GNS label */, + 1, + &rd, + &namestore_put_cont, + NULL); + return; + } + if (0 == strcmp (name, "caller-ego")) + { + GNUNET_IDENTITY_ego_get_public_key (ego, &pub); + GNUNET_asprintf (&gns_caller_id, + "%s", + GNUNET_GNSRECORD_pkey_to_zkey (&pub)); + call = GNUNET_CONVERSATION_call_start (cfg, + ego, + ego, + gns_name, + &call_speaker, + &call_mic, + &call_event_handler, + NULL); + return; + } +} + + +static void +phone_ego_create_cont (void *cls, + const char *emsg) +{ + op = NULL; + GNUNET_assert (NULL == emsg); +} + + +static void +run (void *cls, + const struct GNUNET_CONFIGURATION_Handle *c, + struct GNUNET_TESTING_Peer *peer) +{ + cfg = c; + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_test, + NULL); + id = GNUNET_IDENTITY_connect (cfg, + &identity_cb, + NULL); + op = GNUNET_IDENTITY_create (id, "phone-ego", &phone_ego_create_cont, NULL); + ns = GNUNET_NAMESTORE_connect (cfg); } int main (int argc, char *argv[]) { - GNUNET_log_setup ("test_conversation_api", - "WARNING", - NULL); - return check (); + if (0 != GNUNET_TESTING_peer_run ("test_conversation_api", + "test_conversation.conf", + &run, NULL)) + return 1; + return ok; } /* end of test_conversation_api.c */