+ /**
+ * Closure for 'cont'.
+ */
+ void *cont_cls;
+
+};
+
+
+/**
+ * Continuation called when the control message was transmitted.
+ * Calls the original continuation and frees the remaining
+ * resources.
+ *
+ * @param cls the 'struct GNUNET_CORE_PeerRequestHandle'
+ * @param success was the request transmitted?
+ */
+static void
+peer_request_connect_cont (void *cls,
+ int success)
+{
+ struct GNUNET_CORE_PeerRequestHandle *ret = cls;
+
+ if (ret->cont != NULL)
+ ret->cont (ret->cont_cls, success);
+ GNUNET_free (ret);
+}
+
+
+/**
+ * Request that the core should try to connect to a particular peer.
+ * Once the request has been transmitted to the core, the continuation
+ * function will be called. Note that this does NOT mean that a
+ * connection was successfully established -- it only means that the
+ * core will now try. Successful establishment of the connection
+ * will be signalled to the 'connects' callback argument of
+ * 'GNUNET_CORE_connect' only. If the core service does not respond
+ * to our connection attempt within the given time frame, 'cont' will
+ * be called with the TIMEOUT reason code.
+ *
+ * @param h core handle
+ * @param timeout how long to try to talk to core
+ * @param peer who should we connect to
+ * @param cont function to call once the request has been completed (or timed out)
+ * @param cont_cls closure for cont
+ *
+ * @return NULL on error or already connected,
+ * otherwise handle for cancellation
+ */
+struct GNUNET_CORE_PeerRequestHandle *
+GNUNET_CORE_peer_request_connect (struct GNUNET_CORE_Handle *h,
+ struct GNUNET_TIME_Relative timeout,
+ const struct GNUNET_PeerIdentity * peer,
+ GNUNET_CORE_ControlContinuation cont,
+ void *cont_cls)
+{
+ struct GNUNET_CORE_PeerRequestHandle *ret;
+ struct ControlMessage *cm;
+ struct ConnectMessage *msg;
+
+ if (NULL != GNUNET_CONTAINER_multihashmap_get (h->peers,
+ &peer->hashPubKey))
+ return NULL; /* Already connected, means callback should have happened already! */
+
+
+ cm = GNUNET_malloc (sizeof (struct ControlMessage) +
+ sizeof (struct ConnectMessage));
+ msg = (struct ConnectMessage*) &cm[1];
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_REQUEST_CONNECT);
+ msg->header.size = htons (sizeof (struct ConnectMessage));
+ msg->reserved = htonl (0);
+ msg->timeout = GNUNET_TIME_relative_hton (timeout);
+ msg->peer = *peer;
+ GNUNET_CONTAINER_DLL_insert (h->control_pending_head,
+ h->control_pending_tail,
+ cm);
+ ret = GNUNET_malloc (sizeof (struct GNUNET_CORE_PeerRequestHandle));
+ ret->h = h;
+ ret->cm = cm;
+ ret->cont = cont;
+ ret->cont_cls = cont_cls;
+ cm->cont = &peer_request_connect_cont;
+ cm->cont_cls = ret;
+#if DEBUG_CORE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Queueing REQUEST_CONNECT request\n");
+#endif
+ if (h->control_pending_head == cm)
+ trigger_next_request (h, GNUNET_NO);
+ return ret;
+}
+
+
+/**
+ * Cancel a pending request to connect to a particular peer. Must not
+ * be called after the 'cont' function was invoked.
+ *
+ * @param req request handle that was returned for the original request
+ */
+void
+GNUNET_CORE_peer_request_connect_cancel (struct GNUNET_CORE_PeerRequestHandle *req)
+{
+ struct GNUNET_CORE_Handle *h = req->h;
+ struct ControlMessage *cm = req->cm;
+
+ GNUNET_CONTAINER_DLL_remove (h->control_pending_head,
+ h->control_pending_tail,
+ cm);
+ GNUNET_free (cm);
+ GNUNET_free (req);
+}
+
+
+/* ****************** GNUNET_CORE_peer_change_preference ******************** */
+
+
+struct GNUNET_CORE_InformationRequestContext
+{
+
+ /**
+ * Our connection to the service.
+ */
+ struct GNUNET_CORE_Handle *h;
+
+ /**
+ * Function to call with the information.
+ */
+ GNUNET_CORE_PeerConfigurationInfoCallback info;
+
+ /**
+ * Closure for info.
+ */
+ void *info_cls;
+
+ /**
+ * Link to control message, NULL if CM was sent.
+ */
+ struct ControlMessage *cm;
+
+ /**
+ * Link to peer record.
+ */
+ struct PeerRecord *pr;
+};
+
+
+/**
+ * CM was sent, remove link so we don't double-free.
+ *
+ * @param cls the 'struct GNUNET_CORE_InformationRequestContext'
+ * @param success were we successful?
+ */
+static void
+change_preference_send_continuation (void *cls,
+ int success)
+{
+ struct GNUNET_CORE_InformationRequestContext *irc = cls;
+
+ irc->cm = NULL;
+}
+
+
+/**
+ * Obtain statistics and/or change preferences for the given peer.
+ *
+ * @param h core handle
+ * @param peer identifies the peer
+ * @param timeout after how long should we give up (and call "info" with NULL
+ * for "peer" to signal an error)?
+ * @param bw_out set to the current bandwidth limit (sending) for this peer,
+ * caller should set "bw_out" to "-1" to avoid changing
+ * the current value; otherwise "bw_out" will be lowered to
+ * the specified value; passing a pointer to "0" can be used to force
+ * us to disconnect from the peer; "bw_out" might not increase
+ * as specified since the upper bound is generally
+ * determined by the other peer!
+ * @param amount reserve N bytes for receiving, negative
+ * amounts can be used to undo a (recent) reservation;
+ * @param preference increase incoming traffic share preference by this amount;
+ * in the absence of "amount" reservations, we use this
+ * preference value to assign proportional bandwidth shares
+ * to all connected peers
+ * @param info function to call with the resulting configuration information
+ * @param info_cls closure for info
+ * @return NULL on error
+ */
+struct GNUNET_CORE_InformationRequestContext *
+GNUNET_CORE_peer_change_preference (struct GNUNET_CORE_Handle *h,
+ const struct GNUNET_PeerIdentity *peer,
+ struct GNUNET_TIME_Relative timeout,
+ struct GNUNET_BANDWIDTH_Value32NBO bw_out,
+ int32_t amount,
+ uint64_t preference,
+ GNUNET_CORE_PeerConfigurationInfoCallback info,
+ void *info_cls)
+{
+ struct GNUNET_CORE_InformationRequestContext *irc;
+ struct PeerRecord *pr;
+ struct RequestInfoMessage *rim;
+ struct ControlMessage *cm;
+
+ pr = GNUNET_CONTAINER_multihashmap_get (h->peers,
+ &peer->hashPubKey);
+ if (NULL == pr)