/** * Removes a the give peer from the peer array * * @param peer the peer to be removed */ static void peer_list_remove (struct Peer *peer) { unsigned int orig_size; uint32_t id; if (GNUNET_NO == peer->is_remote) GST_num_local_peers--; GST_peer_list[peer->id] = NULL; orig_size = GST_peer_list_size; while (GST_peer_list_size >= LIST_GROW_STEP) { for (id = GST_peer_list_size - 1; (id >= GST_peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX); id--) if (NULL != GST_peer_list[id]) break; if (id != ((GST_peer_list_size - LIST_GROW_STEP) - 1)) break; GST_peer_list_size -= LIST_GROW_STEP; } if (orig_size == GST_peer_list_size) return; GST_peer_list = GNUNET_realloc (GST_peer_list, sizeof (struct Peer *) * GST_peer_list_size); }
/** * Function to call to start a peer_create type operation once all * queues the operation is part of declare that the * operation can be activated. * * @param cls the closure from GNUNET_TESTBED_operation_create_() */ static void opstart_peer_create (void *cls) { struct OperationContext *opc = cls; struct PeerCreateData *data; struct GNUNET_TESTBED_PeerCreateMessage *msg; char *config; char *xconfig; size_t c_size; size_t xc_size; uint16_t msize; GNUNET_assert (OP_PEER_CREATE == opc->type); data = opc->data; GNUNET_assert (NULL != data); GNUNET_assert (NULL != data->peer); opc->state = OPC_STATE_STARTED; config = GNUNET_CONFIGURATION_serialize (data->cfg, &c_size); xc_size = GNUNET_TESTBED_compress_config_ (config, c_size, &xconfig); GNUNET_free (config); msize = xc_size + sizeof (struct GNUNET_TESTBED_PeerCreateMessage); msg = GNUNET_realloc (xconfig, msize); memmove (&msg[1], msg, xc_size); msg->header.size = htons (msize); msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER); msg->operation_id = GNUNET_htonll (opc->id); msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (data->peer->host)); msg->peer_id = htonl (data->peer->unique_id); msg->config_size = htonl (c_size); GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc); GNUNET_TESTBED_queue_message_ (opc->c, &msg->header); }
/** * Send data to be logged to the logger service. The data will be buffered and * will be sent upon an explicit call to GNUNET_TESTBED_LOGGER_flush() or upon * exceeding a threshold size. * * @param h the logger handle * @param data the data to send; * @param size how many bytes of data to send */ void GNUNET_TESTBED_LOGGER_write (struct GNUNET_TESTBED_LOGGER_Handle *h, const void *data, size_t size) { size_t fit_size; GNUNET_assert (0 != size); GNUNET_assert (NULL != data); GNUNET_assert (size < (GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_MessageHeader))); fit_size = sizeof (struct GNUNET_MessageHeader) + h->bs + size; if ( GNUNET_SERVER_MAX_MESSAGE_SIZE < fit_size ) dispatch_buffer (h); if (NULL == h->buf) { h->buf = GNUNET_malloc (size); h->bs = size; memcpy (h->buf, data, size); return; } h->buf = GNUNET_realloc (h->buf, h->bs + size); memcpy (h->buf + h->bs, data, size); h->bs += size; return; }
/** * Queue a message part for transmission. * * The message part is added to the current message buffer. * When this buffer is full, it is added to the transmission queue. * * @param tmit * Transmission handle. * @param msg * Message part, or NULL. * @param tmit_now * Transmit message now, or wait for buffer to fill up? * #GNUNET_YES or #GNUNET_NO. */ static void transmit_queue_insert (struct GNUNET_PSYC_TransmitHandle *tmit, const struct GNUNET_MessageHeader *msg, uint8_t tmit_now) { uint16_t size = (NULL != msg) ? ntohs (msg->size) : 0; LOG (GNUNET_ERROR_TYPE_DEBUG, "Queueing message part of type %u and size %u (tmit_now: %u)).\n", NULL != msg ? ntohs (msg->type) : 0, size, tmit_now); if (NULL != tmit->msg) { if (NULL == msg || GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < tmit->msg->size + size) { /* End of message or buffer is full, add it to transmission queue * and start with empty buffer */ tmit->msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); tmit->msg->size = htons (tmit->msg->size); GNUNET_CLIENT_MANAGER_transmit (tmit->client, tmit->msg); tmit->msg = NULL; tmit->acks_pending++; } else { /* Message fits in current buffer, append */ tmit->msg = GNUNET_realloc (tmit->msg, tmit->msg->size + size); memcpy ((char *) tmit->msg + tmit->msg->size, msg, size); tmit->msg->size += size; } } if (NULL == tmit->msg && NULL != msg) { /* Empty buffer, copy over message. */ tmit->msg = GNUNET_malloc (sizeof (*tmit->msg) + size); tmit->msg->size = sizeof (*tmit->msg) + size; memcpy (&tmit->msg[1], msg, size); } if (NULL != tmit->msg && (GNUNET_YES == tmit_now || (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < tmit->msg->size + sizeof (struct GNUNET_MessageHeader)))) { /* End of message or buffer is full, add it to transmission queue. */ tmit->msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); tmit->msg->size = htons (tmit->msg->size); GNUNET_CLIENT_MANAGER_transmit (tmit->client, tmit->msg); tmit->msg = NULL; tmit->acks_pending++; } }
/** * Send the buffered data to the service * * @param h the logger handle */ static void dispatch_buffer (struct GNUNET_TESTBED_LOGGER_Handle *h) { struct GNUNET_MessageHeader *msg; size_t msize; msize = sizeof (struct GNUNET_MessageHeader) + h->bs; msg = GNUNET_realloc (h->buf, msize); h->buf = NULL; memmove (&msg[1], msg, h->bs); h->bs = 0; msg->type = htons (GNUNET_MESSAGE_TYPE_TESTBED_LOGGER_MSG); msg->size = htons (msize); queue_message (h, msg); }
/** * Append a message to the transmission context. * All messages in the context will be sent by * the transmit_context_run method. * * @param tc context to use * @param msg message to append */ void GNUNET_SERVER_transmit_context_append_message (struct GNUNET_SERVER_TransmitContext *tc, const struct GNUNET_MessageHeader *msg) { struct GNUNET_MessageHeader *m; uint16_t size; size = ntohs (msg->size); tc->buf = GNUNET_realloc (tc->buf, tc->total + size); m = (struct GNUNET_MessageHeader *) &tc->buf[tc->total]; tc->total += size; memcpy (m, msg, size); }
/** * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages * * @param cls NULL * @param client identification of the client * @param message the actual message */ static void handle_slave_get_config (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg; struct Slave *slave; struct GNUNET_TESTBED_SlaveConfiguration *reply; const struct GNUNET_CONFIGURATION_Handle *cfg; char *config; char *xconfig; size_t config_size; size_t xconfig_size; size_t reply_size; uint64_t op_id; uint32_t slave_id; msg = (struct GNUNET_TESTBED_SlaveGetConfigurationMessage *) message; slave_id = ntohl (msg->slave_id); op_id = GNUNET_ntohll (msg->operation_id); if ((GST_slave_list_size <= slave_id) || (NULL == GST_slave_list[slave_id])) { /* FIXME: Add forwardings for this type of message here.. */ GST_send_operation_fail_msg (client, op_id, "Slave not found"); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } slave = GST_slave_list[slave_id]; GNUNET_assert (NULL != (cfg = GNUNET_TESTBED_host_get_cfg_ (GST_host_list[slave->host_id]))); config = GNUNET_CONFIGURATION_serialize (cfg, &config_size); xconfig_size = GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig); GNUNET_free (config); reply_size = xconfig_size + sizeof (struct GNUNET_TESTBED_SlaveConfiguration); GNUNET_break (reply_size <= UINT16_MAX); GNUNET_break (config_size <= UINT16_MAX); reply = GNUNET_realloc (xconfig, reply_size); (void) memmove (&reply[1], reply, xconfig_size); reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION); reply->header.size = htons ((uint16_t) reply_size); reply->slave_id = msg->slave_id; reply->operation_id = msg->operation_id; reply->config_size = htons ((uint16_t) config_size); GST_queue_message (client, &reply->header); GNUNET_SERVER_receive_done (client, GNUNET_OK); }
/** * Append a message to the transmission context. * All messages in the context will be sent by * the transmit_context_run method. * * @param tc context to use * @param data what to append to the result message * @param length length of data * @param type type of the message */ void GNUNET_SERVER_transmit_context_append_data (struct GNUNET_SERVER_TransmitContext *tc, const void *data, size_t length, uint16_t type) { struct GNUNET_MessageHeader *msg; size_t size; GNUNET_assert (length < GNUNET_SERVER_MAX_MESSAGE_SIZE); size = length + sizeof (struct GNUNET_MessageHeader); GNUNET_assert (size > length); tc->buf = GNUNET_realloc (tc->buf, tc->total + size); msg = (struct GNUNET_MessageHeader *) &tc->buf[tc->total]; tc->total += size; msg->size = htons (size); msg->type = htons (type); memcpy (&msg[1], data, length); }
/** * Destroy a host handle. Must only be called once everything * running on that host has been stopped. * * @param host handle to destroy */ void GNUNET_TESTBED_host_destroy (struct GNUNET_TESTBED_Host *host) { struct RegisteredController *rc; uint32_t id; GNUNET_assert (host->id < host_list_size); GNUNET_assert (host_list[host->id] == host); host_list[host->id] = NULL; /* clear registered controllers list */ for (rc = host->rc_head; NULL != rc; rc = host->rc_head) { GNUNET_CONTAINER_DLL_remove (host->rc_head, host->rc_tail, rc); GNUNET_free (rc); } GNUNET_free_non_null ((char *) host->username); GNUNET_free_non_null ((char *) host->hostname); GNUNET_TESTBED_operation_queue_destroy_ (host->opq_parallel_overlay_connect_operations); GNUNET_CONFIGURATION_destroy (host->cfg); GNUNET_free (host); while (host_list_size >= HOST_LIST_GROW_STEP) { for (id = host_list_size - 1; id > host_list_size - HOST_LIST_GROW_STEP; id--) if (NULL != host_list[id]) break; if (id != host_list_size - HOST_LIST_GROW_STEP) break; if (NULL != host_list[id]) break; host_list_size -= HOST_LIST_GROW_STEP; } host_list = GNUNET_realloc (host_list, sizeof (struct GNUNET_TESTBED_Host *) * host_list_size); }
static int check () { #define MAX_TESTVAL 1024 char *ptrs[MAX_TESTVAL]; int i; int j; int k; unsigned int ui; /* GNUNET_malloc/GNUNET_free test */ k = 352; /* random start value */ for (i = 1; i < MAX_TESTVAL; i++) { ptrs[i] = GNUNET_malloc (i); for (j = 0; j < i; j++) ptrs[i][j] = k++; } for (i = MAX_TESTVAL - 1; i >= 1; i--) { for (j = i - 1; j >= 0; j--) if (ptrs[i][j] != (char) --k) return 1; GNUNET_free (ptrs[i]); } /* GNUNET_free_non_null test */ GNUNET_free_non_null (NULL); GNUNET_free_non_null (GNUNET_malloc (4)); /* GNUNET_strdup tests */ ptrs[0] = GNUNET_strdup ("bar"); if (0 != strcmp (ptrs[0], "bar")) return 3; /* now realloc */ ptrs[0] = GNUNET_realloc (ptrs[0], 12); strcpy (ptrs[0], "Hello World"); GNUNET_free (ptrs[0]); GNUNET_asprintf (&ptrs[0], "%s %s", "Hello", "World"); GNUNET_assert (strlen (ptrs[0]) == 11); GNUNET_free (ptrs[0]); /* GNUNET_array_grow tests */ ptrs[0] = NULL; ui = 0; GNUNET_array_grow (ptrs[0], ui, 42); if (ui != 42) return 4; GNUNET_array_grow (ptrs[0], ui, 22); if (ui != 22) return 5; for (j = 0; j < 22; j++) ptrs[0][j] = j; GNUNET_array_grow (ptrs[0], ui, 32); for (j = 0; j < 22; j++) if (ptrs[0][j] != j) return 6; for (j = 22; j < 32; j++) if (ptrs[0][j] != 0) return 7; GNUNET_array_grow (ptrs[0], ui, 0); if (i != 0) return 8; if (ptrs[0] != NULL) return 9; return 0; }
/** * We are ready to transmit (or got a timeout). * * @param cls our connection handle * @param tc task context describing why we are here */ static void transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CONNECTION_Handle *connection = cls; GNUNET_CONNECTION_TransmitReadyNotify notify; ssize_t ret; size_t have; LOG (GNUNET_ERROR_TYPE_DEBUG, "transmit_ready running (%p).\n", connection); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != connection->write_task); connection->write_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->nth.timeout_task); if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) { if (NULL != connection->sock) goto SCHEDULE_WRITE; /* ignore shutdown, go again immediately */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmit to `%s' fails, shutdown happened (%p).\n", GNUNET_a2s (connection->addr, connection->addrlen), connection); notify = connection->nth.notify_ready; if (NULL != notify) { connection->nth.notify_ready = NULL; notify (connection->nth.notify_ready_cls, 0, NULL); } return; } if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmit to `%s' fails, time out reached (%p).\n", GNUNET_a2s (connection->addr, connection->addrlen), connection); notify = connection->nth.notify_ready; GNUNET_assert (NULL != notify); connection->nth.notify_ready = NULL; notify (connection->nth.notify_ready_cls, 0, NULL); return; } GNUNET_assert (NULL != connection->sock); if (NULL == tc->write_ready) { /* special circumstances (in particular, PREREQ_DONE after * connect): not yet ready to write, but no "fatal" error either. * Hence retry. */ goto SCHEDULE_WRITE; } if (!GNUNET_NETWORK_fdset_isset (tc->write_ready, connection->sock)) { GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->write_task); /* special circumstances (in particular, shutdown): not yet ready * to write, but no "fatal" error either. Hence retry. */ goto SCHEDULE_WRITE; } GNUNET_assert (connection->write_buffer_off >= connection->write_buffer_pos); if ((NULL != connection->nth.notify_ready) && (connection->write_buffer_size < connection->nth.notify_size)) { connection->write_buffer = GNUNET_realloc (connection->write_buffer, connection->nth.notify_size); connection->write_buffer_size = connection->nth.notify_size; } process_notify (connection); have = connection->write_buffer_off - connection->write_buffer_pos; if (0 == have) { /* no data ready for writing, terminate write loop */ return; } GNUNET_assert (have <= connection->write_buffer_size); GNUNET_assert (have + connection->write_buffer_pos <= connection->write_buffer_size); GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size); RETRY: ret = GNUNET_NETWORK_socket_send (connection->sock, &connection->write_buffer[connection->write_buffer_pos], have); if (-1 == ret) { if (EINTR == errno) goto RETRY; if (GNUNET_SCHEDULER_NO_TASK != connection->write_task) { GNUNET_SCHEDULER_cancel (connection->write_task); connection->write_task = GNUNET_SCHEDULER_NO_TASK; } signal_transmit_error (connection, errno); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection transmitted %u/%u bytes to `%s' (%p)\n", (unsigned int) ret, have, GNUNET_a2s (connection->addr, connection->addrlen), connection); connection->write_buffer_pos += ret; if (connection->write_buffer_pos == connection->write_buffer_off) { /* transmitted all pending data */ connection->write_buffer_pos = 0; connection->write_buffer_off = 0; } if ((0 == connection->write_buffer_off) && (NULL == connection->nth.notify_ready)) return; /* all data sent! */ /* not done writing, schedule more */ SCHEDULE_WRITE: LOG (GNUNET_ERROR_TYPE_DEBUG, "Re-scheduling transmit_ready (more to do) (%p).\n", connection); have = connection->write_buffer_off - connection->write_buffer_pos; GNUNET_assert ((NULL != connection->nth.notify_ready) || (have > 0)); if (GNUNET_SCHEDULER_NO_TASK == connection->write_task) connection->write_task = GNUNET_SCHEDULER_add_write_net ((connection->nth.notify_ready == NULL) ? GNUNET_TIME_UNIT_FOREVER_REL : GNUNET_TIME_absolute_get_remaining (connection->nth.transmit_timeout), connection->sock, &transmit_ready, connection); }
/** * Add incoming data to the receive buffer and call the * callback for all complete messages. * * @param mst tokenizer to use * @param client_identity ID of client for which this is a buffer * @param buf input data to add * @param size number of bytes in buf * @param purge should any excess bytes in the buffer be discarded * (i.e. for packet-based services like UDP) * @param one_shot only call callback once, keep rest of message in buffer * @return GNUNET_OK if we are done processing (need more data) * GNUNET_NO if one_shot was set and we have another message ready * GNUNET_SYSERR if the data stream is corrupt */ int GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst, void *client_identity, const char *buf, size_t size, int purge, int one_shot) { const struct GNUNET_MessageHeader *hdr; size_t delta; uint16_t want; char *ibuf; int need_align; unsigned long offset; int ret; GNUNET_assert (mst->off <= mst->pos); GNUNET_assert (mst->pos <= mst->curr_buf); LOG (GNUNET_ERROR_TYPE_DEBUG, "Server-mst receives %u bytes with %u bytes already in private buffer\n", (unsigned int) size, (unsigned int) (mst->pos - mst->off)); ret = GNUNET_OK; ibuf = (char *) mst->hdr; while (mst->pos > 0) { do_align: GNUNET_assert (mst->pos >= mst->off); if ((mst->curr_buf - mst->off < sizeof (struct GNUNET_MessageHeader)) || (0 != (mst->off % ALIGN_FACTOR))) { /* need to align or need more space */ mst->pos -= mst->off; memmove (ibuf, &ibuf[mst->off], mst->pos); mst->off = 0; } if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader)) { delta = GNUNET_MIN (sizeof (struct GNUNET_MessageHeader) - (mst->pos - mst->off), size); memcpy (&ibuf[mst->pos], buf, delta); mst->pos += delta; buf += delta; size -= delta; } if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader)) { if (purge) { mst->off = 0; mst->pos = 0; } return GNUNET_OK; } hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off]; want = ntohs (hdr->size); if (want < sizeof (struct GNUNET_MessageHeader)) { GNUNET_break_op (0); return GNUNET_SYSERR; } if ( (mst->curr_buf - mst->off < want) && (mst->off > 0) ) { /* can get more space by moving */ mst->pos -= mst->off; memmove (ibuf, &ibuf[mst->off], mst->pos); mst->off = 0; } if (mst->curr_buf < want) { /* need to get more space by growing buffer */ GNUNET_assert (0 == mst->off); mst->hdr = GNUNET_realloc (mst->hdr, want); ibuf = (char *) mst->hdr; mst->curr_buf = want; } hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off]; if (mst->pos - mst->off < want) { delta = GNUNET_MIN (want - (mst->pos - mst->off), size); GNUNET_assert (mst->pos + delta <= mst->curr_buf); memcpy (&ibuf[mst->pos], buf, delta); mst->pos += delta; buf += delta; size -= delta; } if (mst->pos - mst->off < want) { if (purge) { mst->off = 0; mst->pos = 0; } return GNUNET_OK; } if (one_shot == GNUNET_SYSERR) { /* cannot call callback again, but return value saying that * we have another full message in the buffer */ ret = GNUNET_NO; goto copy; } if (one_shot == GNUNET_YES) one_shot = GNUNET_SYSERR; mst->off += want; if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr)) return GNUNET_SYSERR; if (mst->off == mst->pos) { /* reset to beginning of buffer, it's free right now! */ mst->off = 0; mst->pos = 0; } } GNUNET_assert (0 == mst->pos); while (size > 0) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Server-mst has %u bytes left in inbound buffer\n", (unsigned int) size); if (size < sizeof (struct GNUNET_MessageHeader)) break; offset = (unsigned long) buf; need_align = (0 != (offset % ALIGN_FACTOR)) ? GNUNET_YES : GNUNET_NO; if (GNUNET_NO == need_align) { /* can try to do zero-copy and process directly from original buffer */ hdr = (const struct GNUNET_MessageHeader *) buf; want = ntohs (hdr->size); if (want < sizeof (struct GNUNET_MessageHeader)) { GNUNET_break_op (0); mst->off = 0; return GNUNET_SYSERR; } if (size < want) break; /* or not: buffer incomplete, so copy to private buffer... */ if (one_shot == GNUNET_SYSERR) { /* cannot call callback again, but return value saying that * we have another full message in the buffer */ ret = GNUNET_NO; goto copy; } if (one_shot == GNUNET_YES) one_shot = GNUNET_SYSERR; if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr)) return GNUNET_SYSERR; buf += want; size -= want; } else { /* need to copy to private buffer to align; * yes, we go a bit more spagetti than usual here */ goto do_align; } } copy: if ((size > 0) && (!purge)) { if (size + mst->pos > mst->curr_buf) { mst->hdr = GNUNET_realloc (mst->hdr, size + mst->pos); ibuf = (char *) mst->hdr; mst->curr_buf = size + mst->pos; } GNUNET_assert (size + mst->pos <= mst->curr_buf); memcpy (&ibuf[mst->pos], buf, size); mst->pos += size; } if (purge) { mst->off = 0; mst->pos = 0; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Server-mst leaves %u bytes in private buffer\n", (unsigned int) (mst->pos - mst->off)); return ret; }