/** * Transmit START message to service. * * @param cls unused * @param size number of bytes available in buf * @param buf where to copy the message * @return number of bytes copied to buf */ static size_t send_start (void *cls, size_t size, void *buf) { struct GNUNET_NSE_Handle *h = cls; struct GNUNET_MessageHeader *msg; h->th = NULL; if (buf == NULL) { /* Connect error... */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutdown while trying to transmit `%s' request.\n", "START"); reschedule_connect (h); return 0; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' request.\n", "START"); GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); msg = (struct GNUNET_MessageHeader *) buf; msg->size = htons (sizeof (struct GNUNET_MessageHeader)); msg->type = htons (GNUNET_MESSAGE_TYPE_NSE_START); GNUNET_CLIENT_receive (h->client, &message_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); return sizeof (struct GNUNET_MessageHeader); }
/** * Transmit next message to service. * * @param cls The 'struct GNUNET_PSYCSTORE_Handle'. * @param size Number of bytes available in buf. * @param buf Where to copy the message. * @return Number of bytes copied to buf. */ static size_t send_next_message (void *cls, size_t size, void *buf) { struct GNUNET_PSYCSTORE_Handle *h = cls; struct GNUNET_PSYCSTORE_OperationHandle *op = h->transmit_head; size_t ret; h->th = NULL; if (NULL == op) return 0; ret = ntohs (op->msg->size); if (ret > size) { reschedule_connect (h); return 0; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending message of type %d to PSYCstore service. ID: %" PRIu64 "\n", ntohs (op->msg->type), op->op_id); memcpy (buf, op->msg, ret); GNUNET_CONTAINER_DLL_remove (h->transmit_head, h->transmit_tail, op); if (NULL == op->res_cb && NULL == op->data_cb) { GNUNET_free (op); } else { GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op); } if (NULL != h->transmit_head) transmit_next (h); if (GNUNET_NO == h->in_receive) { h->in_receive = GNUNET_YES; GNUNET_CLIENT_receive (h->client, &message_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); } return ret; }
/** * Transmit next message to service. * * @param cls the `struct GNUNET_IDENTITY_Handle`. * @param size number of bytes available in @a buf * @param buf where to copy the message * @return number of bytes copied to buf */ static size_t send_next_message (void *cls, size_t size, void *buf) { struct GNUNET_IDENTITY_Handle *h = cls; struct GNUNET_IDENTITY_Operation *op = h->op_head; size_t ret; h->th = NULL; if (NULL == op) return 0; ret = ntohs (op->msg->size); if (ret > size) { reschedule_connect (h); return 0; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending message of type %d to identity service\n", ntohs (op->msg->type)); memcpy (buf, op->msg, ret); if ( (NULL == op->cont) && (NULL == op->cb) ) { GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op); GNUNET_free (op); transmit_next (h); } if (GNUNET_NO == h->in_receive) { h->in_receive = GNUNET_YES; GNUNET_CLIENT_receive (h->client, &message_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); } return ret; }
/** * Type of a function to call when we receive a message * from the service. * * @param cls closure * @param msg message received, NULL on timeout or fatal error */ static void message_handler (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_PSYCSTORE_Handle *h = cls; struct GNUNET_PSYCSTORE_OperationHandle *op; const struct OperationResult *opres; const struct CountersResult *cres; const struct FragmentResult *fres; const struct StateResult *sres; const char *str; if (NULL == msg) { reschedule_connect (h); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Received message of type %d from PSYCstore service.\n", ntohs (msg->type)); uint16_t size = ntohs (msg->size); uint16_t type = ntohs (msg->type); switch (type) { case GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE: if (size < sizeof (struct OperationResult)) { LOG (GNUNET_ERROR_TYPE_ERROR, "Received message of type %d with length %lu bytes. " "Expected >= %lu\n", type, size, sizeof (struct OperationResult)); GNUNET_break (0); reschedule_connect (h); return; } opres = (const struct OperationResult *) msg; str = (const char *) &opres[1]; if ( (size > sizeof (struct OperationResult)) && ('\0' != str[size - sizeof (struct OperationResult) - 1]) ) { GNUNET_break (0); reschedule_connect (h); return; } if (size == sizeof (struct OperationResult)) str = ""; op = find_op_by_id (h, GNUNET_ntohll (opres->op_id)); if (NULL == op) { LOG (GNUNET_ERROR_TYPE_DEBUG, "No callback registered for operation with ID %" PRIu64 ".\n", type, GNUNET_ntohll (opres->op_id)); } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "Received result message (type %d) with operation ID: %" PRIu64 "\n", type, op->op_id); int64_t result_code = GNUNET_ntohll (opres->result_code) + INT64_MIN; GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op); if (NULL != op->res_cb) { const struct StateSyncRequest *ssreq; switch (ntohs (op->msg->type)) { case GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_SYNC: ssreq = (const struct StateSyncRequest *) op->msg; if (!(ssreq->flags & STATE_OP_LAST || GNUNET_OK != result_code)) op->res_cb = NULL; break; } } if (NULL != op->res_cb) op->res_cb (op->cls, result_code, str, size - sizeof (*opres)); GNUNET_free (op); } break; case GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_COUNTERS: if (size != sizeof (struct CountersResult)) { LOG (GNUNET_ERROR_TYPE_ERROR, "Received message of type %d with length %lu bytes. " "Expected %lu\n", type, size, sizeof (struct CountersResult)); GNUNET_break (0); reschedule_connect (h); return; } cres = (const struct CountersResult *) msg; op = find_op_by_id (h, GNUNET_ntohll (cres->op_id)); if (NULL == op) { LOG (GNUNET_ERROR_TYPE_DEBUG, "No callback registered for operation with ID %" PRIu64 ".\n", type, GNUNET_ntohll (cres->op_id)); } else { GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op); if (NULL != op->data_cb) ((GNUNET_PSYCSTORE_CountersCallback) op->data_cb) (op->cls, ntohl (cres->result_code), GNUNET_ntohll (cres->max_fragment_id), GNUNET_ntohll (cres->max_message_id), GNUNET_ntohll (cres->max_group_generation), GNUNET_ntohll (cres->max_state_message_id)); GNUNET_free (op); } break; case GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_FRAGMENT: if (size < sizeof (struct FragmentResult)) { LOG (GNUNET_ERROR_TYPE_ERROR, "Received message of type %d with length %lu bytes. " "Expected >= %lu\n", type, size, sizeof (struct FragmentResult)); GNUNET_break (0); reschedule_connect (h); return; } fres = (const struct FragmentResult *) msg; struct GNUNET_MULTICAST_MessageHeader *mmsg = (struct GNUNET_MULTICAST_MessageHeader *) &fres[1]; if (size != sizeof (struct FragmentResult) + ntohs (mmsg->header.size)) { LOG (GNUNET_ERROR_TYPE_ERROR, "Received message of type %d with length %lu bytes. " "Expected = %lu\n", type, size, sizeof (struct FragmentResult) + ntohs (mmsg->header.size)); GNUNET_break (0); reschedule_connect (h); return; } op = find_op_by_id (h, GNUNET_ntohll (fres->op_id)); if (NULL == op) { LOG (GNUNET_ERROR_TYPE_DEBUG, "No callback registered for operation with ID %" PRIu64 ".\n", type, GNUNET_ntohll (fres->op_id)); } else { if (NULL != op->data_cb) ((GNUNET_PSYCSTORE_FragmentCallback) op->data_cb) (op->cls, mmsg, ntohl (fres->psycstore_flags)); } break; case GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_STATE: if (size < sizeof (struct StateResult)) { LOG (GNUNET_ERROR_TYPE_ERROR, "Received message of type %d with length %lu bytes. " "Expected >= %lu\n", type, size, sizeof (struct StateResult)); GNUNET_break (0); reschedule_connect (h); return; } sres = (const struct StateResult *) msg; const char *name = (const char *) &sres[1]; uint16_t name_size = ntohs (sres->name_size); if (name_size <= 2 || '\0' != name[name_size - 1]) { LOG (GNUNET_ERROR_TYPE_ERROR, "Received state result message (type %d) with invalid name.\n", type); GNUNET_break (0); reschedule_connect (h); return; } op = find_op_by_id (h, GNUNET_ntohll (sres->op_id)); if (NULL == op) { LOG (GNUNET_ERROR_TYPE_DEBUG, "No callback registered for operation with ID %" PRIu64 ".\n", type, GNUNET_ntohll (sres->op_id)); } else { if (NULL != op->data_cb) ((GNUNET_PSYCSTORE_StateCallback) op->data_cb) (op->cls, name, (char *) &sres[1] + name_size, ntohs (sres->header.size) - sizeof (*sres) - name_size); } break; default: GNUNET_break (0); reschedule_connect (h); return; } GNUNET_CLIENT_receive (h->client, &message_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); }
/** * Type of a function to call when we receive a message * from the service. * * @param cls closure * @param msg message received, NULL on timeout or fatal error */ static void message_handler (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_IDENTITY_Handle *h = cls; struct GNUNET_IDENTITY_Operation *op; struct GNUNET_IDENTITY_Ego *ego; const struct GNUNET_IDENTITY_ResultCodeMessage *rcm; const struct GNUNET_IDENTITY_UpdateMessage *um; const struct GNUNET_IDENTITY_SetDefaultMessage *sdm; struct GNUNET_CRYPTO_EcdsaPublicKey pub; struct GNUNET_HashCode id; const char *str; uint16_t size; uint16_t name_len; if (NULL == msg) { reschedule_connect (h); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Received message of type %d from identity service\n", ntohs (msg->type)); size = ntohs (msg->size); switch (ntohs (msg->type)) { case GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE: if (size < sizeof (struct GNUNET_IDENTITY_ResultCodeMessage)) { GNUNET_break (0); reschedule_connect (h); return; } rcm = (const struct GNUNET_IDENTITY_ResultCodeMessage *) msg; str = (const char *) &rcm[1]; if ( (size > sizeof (struct GNUNET_IDENTITY_ResultCodeMessage)) && ('\0' != str[size - sizeof (struct GNUNET_IDENTITY_ResultCodeMessage) - 1]) ) { GNUNET_break (0); reschedule_connect (h); return; } if (size == sizeof (struct GNUNET_IDENTITY_ResultCodeMessage)) str = NULL; op = h->op_head; GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op); GNUNET_CLIENT_receive (h->client, &message_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); if (NULL != op->cont) op->cont (op->cls, str); else if (NULL != op->cb) op->cb (op->cls, NULL, NULL, NULL); GNUNET_free (op); break; case GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE: if (size < sizeof (struct GNUNET_IDENTITY_UpdateMessage)) { GNUNET_break (0); reschedule_connect (h); return; } um = (const struct GNUNET_IDENTITY_UpdateMessage *) msg; name_len = ntohs (um->name_len); str = (const char *) &um[1]; if ( (size != name_len + sizeof (struct GNUNET_IDENTITY_UpdateMessage)) || ( (0 != name_len) && ('\0' != str[name_len - 1])) ) { GNUNET_break (0); reschedule_connect (h); return; } if (GNUNET_YES == ntohs (um->end_of_list)) { /* end of initial list of data */ GNUNET_CLIENT_receive (h->client, &message_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); if (NULL != h->cb) h->cb (h->cb_cls, NULL, NULL, NULL); break; } GNUNET_CRYPTO_ecdsa_key_get_public (&um->private_key, &pub); GNUNET_CRYPTO_hash (&pub, sizeof (pub), &id); if (0 == name_len) str = NULL; else str = (const char *) &um[1]; ego = GNUNET_CONTAINER_multihashmap_get (h->egos, &id); if (NULL == ego) { /* ego was created */ if (NULL == str) { /* deletion of unknown ego? not allowed */ GNUNET_break (0); reschedule_connect (h); return; } ego = GNUNET_new (struct GNUNET_IDENTITY_Ego); ego->pk = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey); *ego->pk = um->private_key; ego->name = GNUNET_strdup (str); ego->id = id; GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_put (h->egos, &ego->id, ego, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); } if (NULL == str) { /* ego was deleted */ GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (h->egos, &ego->id, ego)); } else { /* ego changed name */ GNUNET_free (ego->name); ego->name = GNUNET_strdup (str); } GNUNET_CLIENT_receive (h->client, &message_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); /* inform application about change */ if (NULL != h->cb) h->cb (h->cb_cls, ego, &ego->ctx, str); if (NULL == str) { GNUNET_free (ego->pk); GNUNET_free (ego->name); GNUNET_free (ego); } break; case GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT: if (size < sizeof (struct GNUNET_IDENTITY_SetDefaultMessage)) { GNUNET_break (0); reschedule_connect (h); return; } sdm = (const struct GNUNET_IDENTITY_SetDefaultMessage *) msg; GNUNET_break (0 == ntohs (sdm->reserved)); name_len = ntohs (sdm->name_len); str = (const char *) &sdm[1]; if ( (size != name_len + sizeof (struct GNUNET_IDENTITY_SetDefaultMessage)) || ( (0 != name_len) && ('\0' != str[name_len - 1]) ) ) { GNUNET_break (0); reschedule_connect (h); return; } /* Note: we know which service this should be for, so we're not really using 'str' henceforth */ GNUNET_CRYPTO_ecdsa_key_get_public (&sdm->private_key, &pub); GNUNET_CRYPTO_hash (&pub, sizeof (pub), &id); ego = GNUNET_CONTAINER_multihashmap_get (h->egos, &id); if (NULL == ego) { GNUNET_break (0); reschedule_connect (h); return; } op = h->op_head; if (NULL == op) { GNUNET_break (0); reschedule_connect (h); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received SET_DEFAULT message from identity service\n"); GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op); GNUNET_CLIENT_receive (h->client, &message_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); if (NULL != op->cb) op->cb (op->cls, ego, &ego->ctx, ego->name); GNUNET_free (op); break; default: GNUNET_break (0); reschedule_connect (h); return; } }