/** * 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_NSE_Handle *h = cls; const struct GNUNET_NSE_ClientMessage *client_msg; if (msg == NULL) { /* Error, timeout, death */ GNUNET_CLIENT_disconnect (h->client); h->client = NULL; h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h); return; } if ((ntohs (msg->size) != sizeof (struct GNUNET_NSE_ClientMessage)) || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_NSE_ESTIMATE)) { GNUNET_break (0); return; } client_msg = (const struct GNUNET_NSE_ClientMessage *) msg; h->recv_cb (h->recv_cb_cls, GNUNET_TIME_absolute_ntoh (client_msg->timestamp), GNUNET_ntoh_double (client_msg->size_estimate), GNUNET_ntoh_double (client_msg->std_deviation)); GNUNET_CLIENT_receive (h->client, &message_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); }
/** * 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); }
/** * Send the 'TEST' message to the service. If successful, prepare to * receive the reply. * * @param cls the `struct GNUNET_CLIENT_TestHandle` of the test * @param size number of bytes available in @a buf * @param buf where to write the message * @return number of bytes written to @a buf */ static size_t write_test (void *cls, size_t size, void *buf) { struct GNUNET_CLIENT_TestHandle *th = cls; struct GNUNET_MessageHeader *msg; th->th = NULL; if (size < sizeof (struct GNUNET_MessageHeader)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to transmit TEST request.\n"); service_test_report (th, GNUNET_NO); return 0; /* client disconnected */ } LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' request.\n", "TEST"); msg = (struct GNUNET_MessageHeader *) buf; msg->type = htons (GNUNET_MESSAGE_TYPE_TEST); msg->size = htons (sizeof (struct GNUNET_MessageHeader)); GNUNET_CLIENT_receive (th->client, &confirm_handler, th, GNUNET_TIME_absolute_get_remaining (th->test_deadline)); return sizeof (struct GNUNET_MessageHeader); }
/** * Handler for ARM 'termination' reply (failure to receive). * * @param cls our "struct GNUNET_ARM_Handle" * @param msg expected to be NULL */ static void arm_termination_handler (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_ARM_Handle *h = cls; struct ARMControlMessage *cm; if (NULL != msg) { GNUNET_break (0); GNUNET_CLIENT_receive (h->client, &arm_termination_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); return; } cm = h->thm; h->thm = NULL; h->currently_down = GNUNET_YES; GNUNET_CLIENT_disconnect (h->client); h->client = NULL; if (NULL != cm->result_cont) cm->result_cont (cm->cont_cls, GNUNET_ARM_REQUEST_SENT_OK, (const char *) &cm->msg[1], GNUNET_ARM_RESULT_STOPPED); GNUNET_free (cm->msg); GNUNET_free (cm); }
/** * If possible, write a shutdown message to the target * buffer and destroy the client connection. * * @param cls the "struct GNUNET_CLIENT_Connection" to destroy * @param size number of bytes available in buf * @param buf NULL on error, otherwise target buffer * @return number of bytes written to buf */ static size_t write_shutdown (void *cls, size_t size, void *buf) { struct GNUNET_MessageHeader *msg; struct ShutdownContext *shutdown_ctx = cls; if (size < sizeof (struct GNUNET_MessageHeader)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Failed to transmit shutdown request to client.\n")); shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_SYSERR); GNUNET_CLIENT_disconnect (shutdown_ctx->sock); GNUNET_free (shutdown_ctx); return 0; /* client disconnected */ } GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler, shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL); shutdown_ctx->cancel_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (shutdown_ctx->timeout), &service_shutdown_cancel, shutdown_ctx); msg = (struct GNUNET_MessageHeader *) buf; msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN); msg->size = htons (sizeof (struct GNUNET_MessageHeader)); return sizeof (struct GNUNET_MessageHeader); }
/** * We've transmitted the iteration request. Now get ready to process * the results (or handle transmission error). * * @param cls the 'struct GNUNET_PEERINFO_IteratorContext' * @param emsg error message, NULL if transmission worked */ static void iterator_start_receive (void *cls, const char *emsg) { struct GNUNET_PEERINFO_IteratorContext *ic = cls; struct GNUNET_PEERINFO_Handle *h = ic->h; GNUNET_PEERINFO_Processor cb; void *cb_cls; ic->ac = NULL; if (NULL != emsg) { cb = ic->callback; cb_cls = ic->callback_cls; GNUNET_PEERINFO_iterate_cancel (ic); reconnect (h); if (NULL != cb) cb (cb_cls, NULL, NULL, emsg); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for response from `%s' service.\n", "PEERINFO"); ic->in_receive = GNUNET_YES; if (GNUNET_NO == h->in_receive) { h->in_receive = GNUNET_YES; GNUNET_CLIENT_receive (h->client, &peerinfo_handler, h, GNUNET_TIME_absolute_get_remaining (ic->timeout)); } }
/** * Function called to notify a client about the socket * begin ready to queue the message. @a buf will be * NULL and @a size zero if the socket was closed for * writing in the meantime. * * @param cls closure of type `struct TransmitGetResponseContext *` * @param size number of bytes available in @a buf * @param buf where the callee should write the message * @return number of bytes written to @a buf */ static size_t transmit_for_response (void *cls, size_t size, void *buf) { struct TransmitGetResponseContext *tc = cls; uint16_t msize; tc->client->tag = NULL; msize = ntohs (tc->hdr->size); if (NULL == buf) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Could not submit request, not expecting to receive a response.\n"); if (NULL != tc->rn) tc->rn (tc->rn_cls, NULL); GNUNET_free (tc); return 0; } GNUNET_assert (size >= msize); memcpy (buf, tc->hdr, msize); GNUNET_CLIENT_receive (tc->client, tc->rn, tc->rn_cls, GNUNET_TIME_absolute_get_remaining (tc->timeout)); GNUNET_free (tc); return msize; }
/** * We can now transmit a message to NAMESTORE. Do it. * * @param cls the 'struct GNUNET_NAMESTORE_Handle' * @param size number of bytes we can transmit * @param buf where to copy the messages * @return number of bytes copied into buf */ static size_t transmit_message_to_namestore (void *cls, size_t size, void *buf) { struct GNUNET_NAMESTORE_Handle *h = cls; struct PendingMessage *p; size_t ret; char *cbuf; h->th = NULL; if ((size == 0) || (buf == NULL)) { force_reconnect (h); return 0; } ret = 0; cbuf = buf; while ((NULL != (p = h->pending_head)) && (p->size <= size)) { memcpy (&cbuf[ret], &p[1], p->size); ret += p->size; size -= p->size; GNUNET_CONTAINER_DLL_remove (h->pending_head, h->pending_tail, p); if (GNUNET_YES == p->is_init) GNUNET_CLIENT_receive (h->client, &process_namestore_message, h, GNUNET_TIME_UNIT_FOREVER_REL); GNUNET_free (p); } do_transmit (h); return ret; }
/** * Callback called by notify_transmit_ready; sends DNS replies * to the DNS service. * * @param cls the struct GNUNET_DNS_Handle * @param size number of bytes available in buf * @param buf where to copy the message for transmission * @return number of bytes copied to buf */ static size_t send_response (void *cls, size_t size, void *buf) { struct GNUNET_DNS_Handle *dh = cls; struct ReplyQueueEntry *qe; size_t len; dh->dns_transmit_handle = NULL; if (NULL == buf) { disconnect (dh); dh->reconnect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect, dh); return 0; } qe = dh->rq_head; if (NULL == qe) return 0; len = ntohs (qe->msg->size); if (len > size) { dh->dns_transmit_handle = GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection, len, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NO, &send_response, dh); return 0; } memcpy (buf, qe->msg, len); GNUNET_CONTAINER_DLL_remove (dh->rq_head, dh->rq_tail, qe); GNUNET_free (qe); if (GNUNET_NO == dh->in_receive) { dh->in_receive = GNUNET_YES; GNUNET_CLIENT_receive (dh->dns_connection, &request_handler, dh, GNUNET_TIME_UNIT_FOREVER_REL); } if (NULL != (qe = dh->rq_head)) { dh->dns_transmit_handle = GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection, ntohs (qe->msg->size), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NO, &send_response, dh); } return len; }
/** * Transmit a join request to the chat service. * * @param cls closure, pointer to the 'struct GNUNET_CHAT_Room' * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_join_request (void *cls, size_t size, void *buf) { struct GNUNET_CHAT_Room *chat_room = cls; struct JoinRequestMessage *join_msg; char *room; char *meta; size_t room_len; ssize_t meta_len; size_t size_of_join; if (NULL == buf) { #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not transmit join request, retrying...\n"); #endif rejoin_room (chat_room); return 0; } #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting join request to the service\n"); #endif room_len = strlen (chat_room->room_name); meta_len = GNUNET_CONTAINER_meta_data_get_serialized_size (chat_room->member_info); size_of_join = sizeof (struct JoinRequestMessage) + meta_len + room_len; GNUNET_assert (size >= size_of_join); join_msg = buf; join_msg->header.size = htons (size); join_msg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST); join_msg->msg_options = htonl (chat_room->msg_options); join_msg->room_name_len = htons (room_len); join_msg->reserved = htons (0); join_msg->reserved2 = htonl (0); GNUNET_CRYPTO_rsa_key_get_public (chat_room->my_private_key, &join_msg->public_key); room = (char *) &join_msg[1]; memcpy (room, chat_room->room_name, room_len); meta = &room[room_len]; if (GNUNET_SYSERR == GNUNET_CONTAINER_meta_data_serialize (chat_room->member_info, &meta, meta_len, GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not serialize metadata\n")); return 0; } GNUNET_CLIENT_receive (chat_room->client, &receive_results, chat_room, GNUNET_TIME_UNIT_FOREVER_REL); return size_of_join; }
/** * Transmit the next pending message, called by notify_transmit_ready * * @param cls the DHT handle * @param size number of bytes available in @a buf for transmission * @param buf where to copy messages for the service * @return number of bytes written to @a buf */ static size_t transmit_pending (void *cls, size_t size, void *buf) { struct GNUNET_DHT_Handle *handle = cls; struct PendingMessage *head; size_t tsize; handle->th = NULL; if (NULL == buf) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission to DHT service failed! Reconnecting!\n"); do_disconnect (handle); return 0; } if (NULL == (head = handle->pending_head)) return 0; tsize = ntohs (head->msg->size); if (size < tsize) { process_pending_messages (handle); return 0; } memcpy (buf, head->msg, tsize); GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail, head); head->in_pending_queue = GNUNET_NO; if (NULL != head->cont) { head->cont (head->cont_cls, NULL); head->cont = NULL; head->cont_cls = NULL; } if (GNUNET_YES == head->free_on_send) GNUNET_free (head); process_pending_messages (handle); LOG (GNUNET_ERROR_TYPE_DEBUG, "Forwarded request of %u bytes to DHT service\n", (unsigned int) tsize); if (GNUNET_NO == handle->in_receive) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting to process replies from DHT\n"); handle->in_receive = GNUNET_YES; GNUNET_CLIENT_receive (handle->client, &service_message_handler, handle, GNUNET_TIME_UNIT_FOREVER_REL); } return tsize; }
/** * Function called on each response from the FS * service with information about indexed files. * * @param cls closure (of type "struct GNUNET_FS_GetIndexedContext*") * @param msg message with indexing information */ static void handle_index_info (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_FS_GetIndexedContext *gic = cls; const struct IndexInfoMessage *iim; uint16_t msize; const char *filename; if (NULL == msg) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Failed to receive response for `%s' request from `%s' service.\n"), "GET_INDEXED", "fs"); (void) gic->iterator (gic->iterator_cls, NULL, NULL); GNUNET_FS_get_indexed_files_cancel (gic); return; } if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_END) { /* normal end-of-list */ (void) gic->iterator (gic->iterator_cls, NULL, NULL); GNUNET_FS_get_indexed_files_cancel (gic); return; } msize = ntohs (msg->size); iim = (const struct IndexInfoMessage *) msg; filename = (const char *) &iim[1]; if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_ENTRY) || (msize <= sizeof (struct IndexInfoMessage)) || (filename[msize - sizeof (struct IndexInfoMessage) - 1] != '\0')) { /* bogus reply */ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Failed to receive valid response for `%s' request from `%s' service.\n"), "GET_INDEXED", "fs"); (void) gic->iterator (gic->iterator_cls, NULL, NULL); GNUNET_FS_get_indexed_files_cancel (gic); return; } if (GNUNET_OK != gic->iterator (gic->iterator_cls, filename, &iim->file_id)) { GNUNET_FS_get_indexed_files_cancel (gic); return; } /* get more */ GNUNET_CLIENT_receive (gic->client, &handle_index_info, gic, GNUNET_CONSTANTS_SERVICE_TIMEOUT); }
/** * Callback function for data received from the network. Note that * both "available" and "errCode" would be 0 if the read simply timed out. * * @param cls closure * @param buf pointer to received data * @param available number of bytes availabe in "buf", * possibly 0 (on errors) * @param addr address of the sender * @param addrlen size of addr * @param errCode value of errno (on errors receiving) */ static void receive_helper (void *cls, const void *buf, size_t available, const struct sockaddr *addr, socklen_t addrlen, int errCode) { struct GNUNET_CLIENT_Connection *client = cls; struct GNUNET_TIME_Relative remaining; GNUNET_CLIENT_MessageHandler receive_handler; void *receive_handler_cls; GNUNET_assert (GNUNET_NO == client->msg_complete); GNUNET_assert (GNUNET_YES == client->in_receive); client->in_receive = GNUNET_NO; if ((0 == available) || (NULL == client->connection) || (0 != errCode)) { /* signal timeout! */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Timeout in receive_helper, available %u, client->connection %s, errCode `%s'\n", (unsigned int) available, NULL == client->connection ? "NULL" : "non-NULL", STRERROR (errCode)); if (NULL != (receive_handler = client->receiver_handler)) { receive_handler_cls = client->receiver_handler_cls; client->receiver_handler = NULL; receive_handler (receive_handler_cls, NULL); } return; } /* FIXME: optimize for common fast case where buf contains the * entire message and we need no copying... */ /* slow path: append to array */ if (client->received_size < client->received_pos + available) GNUNET_array_grow (client->received_buf, client->received_size, client->received_pos + available); memcpy (&client->received_buf[client->received_pos], buf, available); client->received_pos += available; check_complete (client); /* check for timeout */ remaining = GNUNET_TIME_absolute_get_remaining (client->receive_timeout); if (0 == remaining.rel_value) { /* signal timeout! */ if (NULL != client->receiver_handler) client->receiver_handler (client->receiver_handler_cls, NULL); return; } /* back to receive -- either for more data or to call callback! */ GNUNET_CLIENT_receive (client, client->receiver_handler, client->receiver_handler_cls, remaining); }
/** * We got a response or disconnect after asking regex * to do the search. Handle it. * * @param cls the `struct GNUNET_REGEX_Search` to handle reply for * @param msg NULL on disconnect, otherwise presumably a response */ static void handle_search_response (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_REGEX_Search *s = cls; const struct ResultMessage *result; uint16_t size; uint16_t gpl; uint16_t ppl; if (NULL == msg) { GNUNET_CLIENT_disconnect (s->client); s->client = GNUNET_CLIENT_connect ("regex", s->cfg); retry_search (s); return; } size = ntohs (msg->size); if ( (GNUNET_MESSAGE_TYPE_REGEX_RESULT == ntohs (msg->type)) && (size >= sizeof (struct ResultMessage)) ) { result = (const struct ResultMessage *) msg; gpl = ntohs (result->get_path_length); ppl = ntohs (result->put_path_length); if (size == (sizeof (struct ResultMessage) + (gpl + ppl) * sizeof (struct GNUNET_PeerIdentity))) { const struct GNUNET_PeerIdentity *pid; GNUNET_CLIENT_receive (s->client, &handle_search_response, s, GNUNET_TIME_UNIT_FOREVER_REL); pid = &result->id; LOG (GNUNET_ERROR_TYPE_DEBUG, "Got regex result %s\n", GNUNET_i2s (pid)); s->callback (s->callback_cls, pid, &pid[1], gpl, &pid[1 + gpl], ppl); return; } } GNUNET_break (0); GNUNET_CLIENT_disconnect (s->client); s->client = GNUNET_CLIENT_connect ("regex", s->cfg); retry_search (s); }
/** * Handler for notification messages received from ARM. * * @param cls our "struct GNUNET_ARM_MonitorHandle" * @param msg the message received from the arm service */ static void monitor_notify_handler (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_ARM_MonitorHandle *h = cls; uint16_t msize; const struct GNUNET_ARM_StatusMessage *res; enum GNUNET_ARM_ServiceStatus status; if (NULL == msg) { LOG (GNUNET_ERROR_TYPE_INFO, _("Monitoring client was disconnected from arm service, trying to reconnect.\n")); reconnect_arm_monitor_later (h); return; } msize = ntohs (msg->size); LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing message of type %u and size %u from arm service\n", ntohs (msg->type), msize); switch (ntohs (msg->type)) { case GNUNET_MESSAGE_TYPE_ARM_STATUS: if (msize <= sizeof (struct GNUNET_ARM_StatusMessage)) { GNUNET_break (0); reconnect_arm_monitor_later (h); return; } if (NULL != h->init_timeout_task_id) { GNUNET_SCHEDULER_cancel (h->init_timeout_task_id); h->init_timeout_task_id = NULL; } res = (const struct GNUNET_ARM_StatusMessage *) msg; LOG (GNUNET_ERROR_TYPE_DEBUG, "Received response from ARM for service `%s': %u\n", (const char *) &res[1], ntohs (msg->type)); status = (enum GNUNET_ARM_ServiceStatus) ntohl (res->status); GNUNET_CLIENT_receive (h->monitor, &monitor_notify_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); if (NULL != h->service_status) h->service_status (h->cls, (const char *) &res[1], status); break; default: reconnect_arm_monitor_later (h); return; } }
/** * This receives packets from the DNS service and calls the application to * handle it. * * @param cls the struct GNUNET_DNS_Handle * @param msg message from the service (request) */ static void request_handler (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_DNS_Handle *dh = cls; const struct GNUNET_DNS_Request *req; struct GNUNET_DNS_RequestHandle *rh; size_t payload_length; /* the service disconnected, reconnect after short wait */ if (msg == NULL) { disconnect (dh); dh->reconnect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect, dh); return; } if ( (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST) || (ntohs (msg->size) < sizeof (struct GNUNET_DNS_Request)) ) { /* the service did something strange, reconnect immediately */ GNUNET_break (0); disconnect (dh); dh->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, dh); return; } req = (const struct GNUNET_DNS_Request *) msg; GNUNET_break (ntohl (req->reserved) == 0); payload_length = ntohs (req->header.size) - sizeof (struct GNUNET_DNS_Request); GNUNET_CLIENT_receive (dh->dns_connection, &request_handler, dh, GNUNET_TIME_UNIT_FOREVER_REL); /* finally, pass request to callback for answers */ rh = GNUNET_new (struct GNUNET_DNS_RequestHandle); rh->dh =dh; rh->request_id = req->request_id; rh->generation = dh->generation; dh->pending_requests++; dh->rh (dh->rh_cls, rh, payload_length, (const char*) &req[1]); }
/** * Task executed once we are done transmitting the INIT message. * Starts our 'receive' loop. * * @param cls the 'struct GNUNET_CORE_Handle' * @param success were we successful */ static void init_done_task (void *cls, int success) { struct GNUNET_CORE_Handle *h = cls; if (GNUNET_SYSERR == success) return; /* shutdown */ if (GNUNET_NO == success) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to exchange INIT with core, retrying\n"); if (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK) reconnect_later (h); return; } GNUNET_CLIENT_receive (h->client, &main_notify_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); }
/** * 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; }
static void task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct sockaddr_in sa; struct sockaddr *sap[2]; socklen_t slens[2]; /* test that ill-configured client fails instantly */ GNUNET_assert (NULL == GNUNET_CLIENT_connect ("invalid-service", cfg)); /* test IPC between client and server */ sap[0] = (struct sockaddr *) &sa; slens[0] = sizeof (sa); sap[1] = NULL; slens[1] = 0; memset (&sa, 0, sizeof (sa)); #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = sizeof (sa); #endif sa.sin_family = AF_INET; sa.sin_port = htons (PORT); server = GNUNET_SERVER_create (NULL, NULL, sap, slens, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 10000), GNUNET_NO); GNUNET_assert (server != NULL); handlers[0].callback_cls = cls; handlers[1].callback_cls = cls; GNUNET_SERVER_add_handlers (server, handlers); client = GNUNET_CLIENT_connect (MYNAME, cfg); GNUNET_assert (client != NULL); GNUNET_assert (NULL != GNUNET_CLIENT_notify_transmit_ready (client, sizeof (struct GNUNET_MessageHeader), GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,5), GNUNET_NO, &make_msg, NULL)); GNUNET_CLIENT_receive (client, &recv_bounce, cls, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 10000)); }
/** * Transmit the next pending message, called by notify_transmit_ready * * @param cls the closure * @param size size of pending data * @param buf buffer with pending data * @return size data transmitted */ static size_t transmit_pending (void *cls, size_t size, void *buf) { struct GNUNET_GNS_Handle *handle = cls; char *cbuf = buf; struct PendingMessage *p; size_t tsize; handle->th = NULL; if ((0 == size) || (NULL == buf)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission to GNS service failed!\n"); force_reconnect (handle); return 0; } if (NULL == (p = handle->pending_head)) return 0; tsize = 0; while ((NULL != (p = handle->pending_head)) && (p->size <= size)) { memcpy (&cbuf[tsize], &p[1], p->size); tsize += p->size; size -= p->size; p->transmitted = GNUNET_YES; GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail, p); if (GNUNET_YES != handle->in_receive) { GNUNET_CLIENT_receive (handle->client, &process_message, handle, GNUNET_TIME_UNIT_FOREVER_REL); handle->in_receive = GNUNET_YES; } } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending %u bytes\n", (unsigned int) tsize); process_pending_messages (handle); return tsize; }
/** * 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 handle_client_message (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_MQ_Handle *mq = cls; struct ClientConnectionState *state; state = mq->impl_state; if (NULL == msg) { GNUNET_MQ_inject_error (mq, GNUNET_MQ_ERROR_READ); return; } GNUNET_CLIENT_receive (state->connection, handle_client_message, mq, GNUNET_TIME_UNIT_FOREVER_REL); GNUNET_MQ_inject_message (mq, msg); }
/** * Transmit the monitoring initialization message to the arm service. * * @param cls closure with the 'struct GNUNET_ARM_MonitorHandle' * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_monitoring_init_message (void *cls, size_t size, void *buf) { struct GNUNET_ARM_MonitorHandle *h = cls; struct GNUNET_MessageHeader *msg; uint16_t msize; GNUNET_assert (NULL == h->reconnect_task); GNUNET_assert (NULL == h->init_timeout_task_id); h->cth = NULL; if (NULL == buf) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission failed, initiating reconnect\n"); reconnect_arm_monitor_later (h); return 0; } msize = sizeof (struct GNUNET_MessageHeader); if (size < msize) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Request is too big (%u < %u), not sending it\n", size, msize); h->cth = GNUNET_CLIENT_notify_transmit_ready (h->monitor, msize, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NO, transmit_monitoring_init_message, h); return 0; } msg = buf; msg->size = htons (msize); msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_MONITOR); LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting ARM monitoring init message with %u bytes to arm.\n", (unsigned int) msize); h->init_timeout_task_id = GNUNET_SCHEDULER_add_delayed ( INIT_TIMEOUT, init_timeout_task, h); GNUNET_CLIENT_receive (h->monitor, &monitor_notify_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); return msize; }
/** * Transmit request from queue to datastore service. * * @param cls the 'struct GNUNET_DATASTORE_Handle' * @param size number of bytes that can be copied to buf * @param buf where to copy the drop message * @return number of bytes written to buf */ static size_t transmit_request (void *cls, size_t size, void *buf) { struct GNUNET_DATASTORE_Handle *h = cls; struct GNUNET_DATASTORE_QueueEntry *qe; size_t msize; h->th = NULL; if (NULL == (qe = h->queue_head)) return 0; /* no entry in queue */ if (buf == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to transmit request to DATASTORE.\n"); GNUNET_STATISTICS_update (h->stats, gettext_noop ("# transmission request failures"), 1, GNUNET_NO); do_disconnect (h); return 0; } if (size < (msize = qe->message_size)) { process_queue (h); return 0; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting %u byte request to DATASTORE\n", msize); memcpy (buf, &qe[1], msize); qe->was_transmitted = GNUNET_YES; GNUNET_SCHEDULER_cancel (qe->task); qe->task = GNUNET_SCHEDULER_NO_TASK; GNUNET_assert (GNUNET_NO == h->in_receive); h->in_receive = GNUNET_YES; GNUNET_CLIENT_receive (h->client, &receive_cb, h, GNUNET_TIME_absolute_get_remaining (qe->timeout)); #if INSANE_STATISTICS GNUNET_STATISTICS_update (h->stats, gettext_noop ("# bytes sent to datastore"), 1, GNUNET_NO); #endif return msize; }
static size_t transmit_initial_message (void *cls, size_t size, void *buf) { struct GNUNET_MessageHeader msg; GNUNET_assert (ok == 1); ok = 2; GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); msg.type = htons (MY_TYPE); msg.size = htons (sizeof (struct GNUNET_MessageHeader)); memcpy (buf, &msg, sizeof (struct GNUNET_MessageHeader)); GNUNET_assert (NULL != GNUNET_CLIENT_notify_transmit_ready (cc, sizeof (struct GNUNET_MessageHeader), TIMEOUT, GNUNET_YES, &transmit_second_message, NULL)); GNUNET_CLIENT_receive (cc, &first_reply_handler, NULL, TIMEOUT); return sizeof (struct GNUNET_MessageHeader); }
/** * 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; }
/** * Handler receiving response to service shutdown requests. * First call with NULL: service misbehaving, or something. * First call with GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN: * - service will shutdown * Second call with NULL: * - service has now really shut down. * * @param cls closure * @param msg NULL, indicating socket closure. */ static void service_shutdown_handler (void *cls, const struct GNUNET_MessageHeader *msg) { struct ShutdownContext *shutdown_ctx = cls; if (msg == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service shutdown complete.\n"); if (shutdown_ctx->cont != NULL) shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_NO); GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task); GNUNET_CLIENT_disconnect (shutdown_ctx->sock); GNUNET_free (shutdown_ctx); return; } GNUNET_assert (ntohs (msg->size) == sizeof (struct GNUNET_MessageHeader)); switch (ntohs (msg->type)) { case GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received confirmation for service shutdown.\n"); shutdown_ctx->confirmed = GNUNET_YES; GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler, shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL); break; default: /* Fall through */ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Service shutdown refused!\n"); if (shutdown_ctx->cont != NULL) shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_YES); GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task); GNUNET_CLIENT_disconnect (shutdown_ctx->sock); GNUNET_free (shutdown_ctx); break; } }
/** * Send the 'TEST' message to the service. If successful, prepare to * receive the reply. * * @param cls the 'struct GNUNET_CLIENT_Connection' of the connection to test * @param size number of bytes available in buf * @param buf where to write the message * @return number of bytes written to buf */ static size_t write_test (void *cls, size_t size, void *buf) { struct GNUNET_CLIENT_Connection *client = cls; struct GNUNET_MessageHeader *msg; if (size < sizeof (struct GNUNET_MessageHeader)) { LOG (GNUNET_ERROR_TYPE_DEBUG, _("Failure to transmit TEST request.\n")); service_test_error (client->test_cb, client->test_cb_cls); GNUNET_CLIENT_disconnect (client); return 0; /* client disconnected */ } LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' request.\n", "TEST"); msg = (struct GNUNET_MessageHeader *) buf; msg->type = htons (GNUNET_MESSAGE_TYPE_TEST); msg->size = htons (sizeof (struct GNUNET_MessageHeader)); GNUNET_CLIENT_receive (client, &confirm_handler, client, GNUNET_TIME_absolute_get_remaining (client->test_deadline)); return sizeof (struct GNUNET_MessageHeader); }
/** * Listen for incoming messages on this chat room. Also, support servers going * away/coming back (i.e. rejoin chat room to keep server state up to date). * * @param cls closure, pointer to the 'struct GNUNET_CHAT_Room' * @param msg message received, NULL on timeout or fatal error */ static void receive_results (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_CHAT_Room *chat_room = cls; #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a message from the service\n"); #endif if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & GNUNET_SCHEDULER_get_reason ())) return; if (NULL == msg) { GNUNET_break (0); rejoin_room (chat_room); return; } process_result (chat_room, msg); if (NULL == chat_room->client) return; /* fatal error */ /* continue receiving */ GNUNET_CLIENT_receive (chat_room->client, &receive_results, chat_room, GNUNET_TIME_UNIT_FOREVER_REL); }
/** * Transmit a queued message to the session's client. * * @param cls consensus session * @param size number of bytes available in @a buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t connection_client_transmit_queued (void *cls, size_t size, void *buf) { struct GNUNET_MQ_Handle *mq = cls; const struct GNUNET_MessageHeader *msg; struct ClientConnectionState *state = mq->impl_state; size_t msg_size; GNUNET_assert (NULL != mq); msg = GNUNET_MQ_impl_current (mq); if (NULL == buf) { GNUNET_MQ_inject_error (mq, GNUNET_MQ_ERROR_READ); return 0; } if ( (GNUNET_YES == state->receive_requested) && (GNUNET_NO == state->receive_active) ) { state->receive_active = GNUNET_YES; GNUNET_CLIENT_receive (state->connection, handle_client_message, mq, GNUNET_TIME_UNIT_FOREVER_REL); } msg_size = ntohs (msg->size); GNUNET_assert (size >= msg_size); memcpy (buf, msg, msg_size); state->th = NULL; GNUNET_MQ_impl_send_continue (mq); return msg_size; }
/** * Handler for notification messages received from the core. * * @param cls our `struct GNUNET_CORE_Handle` * @param msg the message received from the core service */ static void main_notify_handler (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_CORE_Handle *h = cls; const struct InitReplyMessage *m; const struct ConnectNotifyMessage *cnm; const struct DisconnectNotifyMessage *dnm; const struct NotifyTrafficMessage *ntm; const struct GNUNET_MessageHeader *em; const struct SendMessageReady *smr; const struct GNUNET_CORE_MessageHandler *mh; GNUNET_CORE_StartupCallback init; struct PeerRecord *pr; struct GNUNET_CORE_TransmitHandle *th; unsigned int hpos; int trigger; uint16_t msize; uint16_t et; if (NULL == msg) { LOG (GNUNET_ERROR_TYPE_INFO, _("Client was disconnected from core service, trying to reconnect.\n")); reconnect_later (h); return; } msize = ntohs (msg->size); LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing message of type %u and size %u from core service\n", ntohs (msg->type), msize); switch (ntohs (msg->type)) { case GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY: if (ntohs (msg->size) != sizeof (struct InitReplyMessage)) { GNUNET_break (0); reconnect_later (h); return; } m = (const struct InitReplyMessage *) msg; GNUNET_break (0 == ntohl (m->reserved)); /* start our message processing loop */ if (GNUNET_YES == h->currently_down) { h->currently_down = GNUNET_NO; trigger_next_request (h, GNUNET_NO); } h->retry_backoff = GNUNET_TIME_UNIT_MILLISECONDS; h->me = m->my_identity; if (NULL != (init = h->init)) { /* mark so we don't call init on reconnect */ h->init = NULL; LOG (GNUNET_ERROR_TYPE_DEBUG, "Connected to core service of peer `%s'.\n", GNUNET_i2s (&h->me)); init (h->cls, &h->me); } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "Successfully reconnected to core service.\n"); } /* fake 'connect to self' */ pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &h->me); GNUNET_assert (NULL == pr); pr = GNUNET_new (struct PeerRecord); pr->peer = h->me; pr->ch = h; GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multipeermap_put (h->peers, &h->me, pr, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); if (NULL != h->connects) h->connects (h->cls, &h->me); break; case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT: if (msize < sizeof (struct ConnectNotifyMessage)) { GNUNET_break (0); reconnect_later (h); return; } cnm = (const struct ConnectNotifyMessage *) msg; if (msize != sizeof (struct ConnectNotifyMessage)) { GNUNET_break (0); reconnect_later (h); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Received notification about connection from `%s'.\n", GNUNET_i2s (&cnm->peer)); if (0 == memcmp (&h->me, &cnm->peer, sizeof (struct GNUNET_PeerIdentity))) { /* connect to self!? */ GNUNET_break (0); return; } pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &cnm->peer); if (NULL != pr) { GNUNET_break (0); reconnect_later (h); return; } pr = GNUNET_new (struct PeerRecord); pr->peer = cnm->peer; pr->ch = h; GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multipeermap_put (h->peers, &cnm->peer, pr, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); if (NULL != h->connects) h->connects (h->cls, &cnm->peer); break; case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT: if (msize != sizeof (struct DisconnectNotifyMessage)) { GNUNET_break (0); reconnect_later (h); return; } dnm = (const struct DisconnectNotifyMessage *) msg; if (0 == memcmp (&h->me, &dnm->peer, sizeof (struct GNUNET_PeerIdentity))) { /* connection to self!? */ GNUNET_break (0); return; } GNUNET_break (0 == ntohl (dnm->reserved)); LOG (GNUNET_ERROR_TYPE_DEBUG, "Received notification about disconnect from `%s'.\n", GNUNET_i2s (&dnm->peer)); pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &dnm->peer); if (NULL == pr) { GNUNET_break (0); reconnect_later (h); return; } trigger = ((pr->prev != NULL) || (pr->next != NULL) || (h->ready_peer_head == pr)); disconnect_and_free_peer_entry (h, &dnm->peer, pr); if (trigger) trigger_next_request (h, GNUNET_NO); break; case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND: if (msize < sizeof (struct NotifyTrafficMessage)) { GNUNET_break (0); reconnect_later (h); return; } ntm = (const struct NotifyTrafficMessage *) msg; if ((msize < sizeof (struct NotifyTrafficMessage) + sizeof (struct GNUNET_MessageHeader)) ) { GNUNET_break (0); reconnect_later (h); return; } em = (const struct GNUNET_MessageHeader *) &ntm[1]; LOG (GNUNET_ERROR_TYPE_DEBUG, "Received message of type %u and size %u from peer `%4s'\n", ntohs (em->type), ntohs (em->size), GNUNET_i2s (&ntm->peer)); if ((GNUNET_NO == h->inbound_hdr_only) && (msize != ntohs (em->size) + sizeof (struct NotifyTrafficMessage))) { GNUNET_break (0); reconnect_later (h); return; } et = ntohs (em->type); for (hpos = 0; hpos < h->hcnt; hpos++) { mh = &h->handlers[hpos]; if (mh->type != et) continue; if ((mh->expected_size != ntohs (em->size)) && (mh->expected_size != 0)) { LOG (GNUNET_ERROR_TYPE_ERROR, "Unexpected message size %u for message of type %u from peer `%4s'\n", htons (em->size), mh->type, GNUNET_i2s (&ntm->peer)); GNUNET_break_op (0); continue; } pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &ntm->peer); if (NULL == pr) { GNUNET_break (0); reconnect_later (h); return; } if (GNUNET_OK != h->handlers[hpos].callback (h->cls, &ntm->peer, em)) { /* error in processing, do not process other messages! */ break; } } if (NULL != h->inbound_notify) h->inbound_notify (h->cls, &ntm->peer, em); break; case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND: if (msize < sizeof (struct NotifyTrafficMessage)) { GNUNET_break (0); reconnect_later (h); return; } ntm = (const struct NotifyTrafficMessage *) msg; if ((msize < sizeof (struct NotifyTrafficMessage) + sizeof (struct GNUNET_MessageHeader)) ) { GNUNET_break (0); reconnect_later (h); return; } em = (const struct GNUNET_MessageHeader *) &ntm[1]; LOG (GNUNET_ERROR_TYPE_DEBUG, "Received notification about transmission to `%s'.\n", GNUNET_i2s (&ntm->peer)); if ((GNUNET_NO == h->outbound_hdr_only) && (msize != ntohs (em->size) + sizeof (struct NotifyTrafficMessage))) { GNUNET_break (0); reconnect_later (h); return; } if (NULL == h->outbound_notify) { GNUNET_break (0); break; } h->outbound_notify (h->cls, &ntm->peer, em); break; case GNUNET_MESSAGE_TYPE_CORE_SEND_READY: if (msize != sizeof (struct SendMessageReady)) { GNUNET_break (0); reconnect_later (h); return; } smr = (const struct SendMessageReady *) msg; pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &smr->peer); if (NULL == pr) { GNUNET_break (0); reconnect_later (h); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Received notification about transmission readiness to `%s'.\n", GNUNET_i2s (&smr->peer)); if (NULL == pr->th.peer) { /* request must have been cancelled between the original request * and the response from core, ignore core's readiness */ break; } th = &pr->th; if (ntohs (smr->smr_id) != th->smr_id) { /* READY message is for expired or cancelled message, * ignore! (we should have already sent another request) */ break; } if ((NULL != pr->prev) || (NULL != pr->next) || (h->ready_peer_head == pr)) { /* we should not already be on the ready list... */ GNUNET_break (0); reconnect_later (h); return; } GNUNET_CONTAINER_DLL_insert (h->ready_peer_head, h->ready_peer_tail, pr); trigger_next_request (h, GNUNET_NO); break; default: reconnect_later (h); return; } GNUNET_CLIENT_receive (h->client, &main_notify_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); }