+/**
+ * Function setting up curl handle and selecting message to send
+ *
+ * @param plugin plugin
+ * @param ps session
+ * @return GNUNET_SYSERR on failure, GNUNET_NO if connecting, GNUNET_YES if ok
+ */
+static int send_check_connections (struct Plugin *plugin, struct Session *ps)
+{
+ CURLMcode mret;
+ struct HTTP_Message * msg;
+
+ struct GNUNET_TIME_Relative timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT;
+
+ if (ps->direction == OUTBOUND)
+ {
+ /* RECV DIRECTION */
+ /* Check if session is connected to receive data, otherwise connect to peer */
+ if (ps->recv_connected == GNUNET_NO)
+ {
+ int fresh = GNUNET_NO;
+ if (ps->recv_endpoint == NULL)
+ {
+ fresh = GNUNET_YES;
+ ps->recv_endpoint = curl_easy_init();
+ }
+#if DEBUG_CURL
+ curl_easy_setopt(ps->recv_endpoint, CURLOPT_VERBOSE, 1L);
+ curl_easy_setopt(ps->recv_endpoint, CURLOPT_DEBUGFUNCTION , &curl_logger);
+ curl_easy_setopt(ps->recv_endpoint, CURLOPT_DEBUGDATA , ps->recv_endpoint);
+#endif
+#if BUILD_HTTPS
+ curl_easy_setopt (ps->recv_endpoint, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
+ curl_easy_setopt(ps->recv_endpoint, CURLOPT_SSL_VERIFYPEER, 0);
+ curl_easy_setopt(ps->recv_endpoint, CURLOPT_SSL_VERIFYHOST, 0);
+#endif
+ curl_easy_setopt(ps->recv_endpoint, CURLOPT_URL, ps->url);
+ curl_easy_setopt(ps->recv_endpoint, CURLOPT_HEADERFUNCTION, &curl_get_header_cb);
+ curl_easy_setopt(ps->recv_endpoint, CURLOPT_WRITEHEADER, ps);
+ curl_easy_setopt(ps->recv_endpoint, CURLOPT_READFUNCTION, curl_send_cb);
+ curl_easy_setopt(ps->recv_endpoint, CURLOPT_READDATA, ps);
+ curl_easy_setopt(ps->recv_endpoint, CURLOPT_WRITEFUNCTION, curl_receive_cb);
+ curl_easy_setopt(ps->recv_endpoint, CURLOPT_WRITEDATA, ps);
+ curl_easy_setopt(ps->recv_endpoint, CURLOPT_TIMEOUT, (long) timeout.rel_value);
+ curl_easy_setopt(ps->recv_endpoint, CURLOPT_PRIVATE, ps);
+ curl_easy_setopt(ps->recv_endpoint, CURLOPT_CONNECTTIMEOUT, HTTP_CONNECT_TIMEOUT);
+ curl_easy_setopt(ps->recv_endpoint, CURLOPT_BUFFERSIZE, 2*GNUNET_SERVER_MAX_MESSAGE_SIZE);
+#if CURL_TCP_NODELAY
+ curl_easy_setopt(ps->recv_endpoint, CURLOPT_TCP_NODELAY, 1);
+#endif
+
+ if (fresh==GNUNET_YES)
+ {
+ mret = curl_multi_add_handle(plugin->multi_handle, ps->recv_endpoint);
+ if (mret != CURLM_OK)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Connection: %X: %s failed at %s:%d: `%s'\n"),
+ ps,
+ "curl_multi_add_handle", __FILE__, __LINE__,
+ curl_multi_strerror (mret));
+ return GNUNET_SYSERR;
+ }
+ }
+ if (plugin->http_curl_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel(plugin->http_curl_task);
+ plugin->http_curl_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ plugin->http_curl_task = GNUNET_SCHEDULER_add_now (&curl_perform, plugin);
+ }
+
+ /* waiting for receive direction */
+ if (ps->recv_connected==GNUNET_NO)
+ return GNUNET_NO;
+
+ /* SEND DIRECTION */
+ /* Check if session is connected to send data, otherwise connect to peer */
+ if ((ps->send_connected == GNUNET_YES) && (ps->send_endpoint!= NULL))
+ {
+ if (ps->send_active == GNUNET_YES)
+ {
+#if DEBUG_CONNECTIONS
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound active, enqueueing message\n",ps);
+#endif
+ return GNUNET_YES;
+ }
+ if (ps->send_active == GNUNET_NO)
+ {
+#if DEBUG_CONNECTIONS
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound paused, unpausing existing connection and enqueueing message\n",ps);
+#endif
+ if (CURLE_OK == curl_easy_pause(ps->send_endpoint,CURLPAUSE_CONT))
+ {
+ ps->send_active=GNUNET_YES;
+ if (plugin->http_curl_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel(plugin->http_curl_task);
+ plugin->http_curl_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ plugin->http_curl_task = GNUNET_SCHEDULER_add_now (&curl_perform, plugin);
+ return GNUNET_YES;
+ }
+ else
+ return GNUNET_SYSERR;
+ }
+ }
+ /* not connected, initiate connection */
+ if (ps->send_connected==GNUNET_NO)
+ {
+ int fresh = GNUNET_NO;
+ if (NULL == ps->send_endpoint)
+ {
+ ps->send_endpoint = curl_easy_init();
+ fresh = GNUNET_YES;
+ }
+ GNUNET_assert (ps->send_endpoint != NULL);
+ GNUNET_assert (NULL != ps->pending_msgs_tail);
+#if DEBUG_CONNECTIONS
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound not connected, initiating connection\n",ps);
+#endif
+ ps->send_active = GNUNET_NO;
+ msg = ps->pending_msgs_tail;
+
+#if DEBUG_CURL
+ curl_easy_setopt(ps->send_endpoint, CURLOPT_VERBOSE, 1L);
+ curl_easy_setopt(ps->send_endpoint, CURLOPT_DEBUGFUNCTION , &curl_logger);
+ curl_easy_setopt(ps->send_endpoint, CURLOPT_DEBUGDATA , ps->send_endpoint);
+#endif
+#if BUILD_HTTPS
+ curl_easy_setopt (ps->send_endpoint, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
+ curl_easy_setopt(ps->send_endpoint, CURLOPT_SSL_VERIFYPEER, 0);
+ curl_easy_setopt(ps->send_endpoint, CURLOPT_SSL_VERIFYHOST, 0);
+#endif
+ curl_easy_setopt(ps->send_endpoint, CURLOPT_URL, ps->url);
+ curl_easy_setopt(ps->send_endpoint, CURLOPT_PUT, 1L);
+ curl_easy_setopt(ps->send_endpoint, CURLOPT_HEADERFUNCTION, &curl_put_header_cb);
+ curl_easy_setopt(ps->send_endpoint, CURLOPT_WRITEHEADER, ps);
+ curl_easy_setopt(ps->send_endpoint, CURLOPT_READFUNCTION, curl_send_cb);
+ curl_easy_setopt(ps->send_endpoint, CURLOPT_READDATA, ps);
+ curl_easy_setopt(ps->send_endpoint, CURLOPT_WRITEFUNCTION, curl_receive_cb);
+ curl_easy_setopt(ps->send_endpoint, CURLOPT_READDATA, ps);
+ curl_easy_setopt(ps->send_endpoint, CURLOPT_TIMEOUT, (long) timeout.rel_value);
+ curl_easy_setopt(ps->send_endpoint, CURLOPT_PRIVATE, ps);
+ curl_easy_setopt(ps->send_endpoint, CURLOPT_CONNECTTIMEOUT, HTTP_CONNECT_TIMEOUT);
+ curl_easy_setopt(ps->send_endpoint, CURLOPT_BUFFERSIZE, 2 * GNUNET_SERVER_MAX_MESSAGE_SIZE);
+#if CURL_TCP_NODELAY
+ curl_easy_setopt(ps->send_endpoint, CURLOPT_TCP_NODELAY, 1);
+#endif
+
+ if (fresh==GNUNET_YES)
+ {
+ mret = curl_multi_add_handle(plugin->multi_handle, ps->send_endpoint);
+ if (mret != CURLM_OK)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Connection: %X: %s failed at %s:%d: `%s'\n"),
+ ps,
+ "curl_multi_add_handle", __FILE__, __LINE__,
+ curl_multi_strerror (mret));
+ return GNUNET_SYSERR;
+ }
+ }
+ }
+ if (plugin->http_curl_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel(plugin->http_curl_task);
+ plugin->http_curl_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ plugin->http_curl_task = GNUNET_SCHEDULER_add_now (&curl_perform, plugin);
+ return GNUNET_YES;
+ }
+ if (ps->direction == INBOUND)
+ {
+ GNUNET_assert (NULL != ps->pending_msgs_tail);
+ if ((ps->recv_connected==GNUNET_YES) && (ps->send_connected==GNUNET_YES) &&
+ (ps->recv_force_disconnect==GNUNET_NO) && (ps->recv_force_disconnect==GNUNET_NO))
+ return GNUNET_YES;
+ }
+ return GNUNET_SYSERR;
+}
+
+/**
+ * select best session to transmit data to peer
+ *
+ * @param pc peer context of target peer
+ * @param addr address of target peer
+ * @param addrlen address length
+ * @param force_address does transport service enforce address?
+ * @param session session passed by transport service
+ * @return selected session
+ *
+ */
+static struct Session * send_select_session (struct HTTP_PeerContext *pc, const void * addr, size_t addrlen, int force_address, struct Session * session)
+{
+ struct Session * tmp = NULL;
+ int addr_given = GNUNET_NO;
+
+ if ((addr!=NULL) && (addrlen>0))
+ addr_given = GNUNET_YES;
+
+ if (force_address == GNUNET_YES)
+ {
+ /* check session given as argument */
+ if ((session != NULL) && (addr_given == GNUNET_YES))
+ {
+ if (0 == memcmp(session->addr, addr, addrlen))
+ {
+ /* connection can not be used, since it is disconnected */
+ if ((session->recv_force_disconnect==GNUNET_NO) && (session->send_force_disconnect==GNUNET_NO))
+ {
+#if DEBUG_SESSION_SELECTION
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Session %X selected: Using session passed by transport to send to forced address \n", session);
+#endif
+ return session;
+ }
+ }
+ }
+ /* check last session used */
+ if ((pc->last_session != NULL)&& (addr_given == GNUNET_YES))
+ {
+ if (0 == memcmp(pc->last_session->addr, addr, addrlen))
+ {
+ /* connection can not be used, since it is disconnected */
+ if ((pc->last_session->recv_force_disconnect==GNUNET_NO) && (pc->last_session->send_force_disconnect==GNUNET_NO))
+ {
+#if DEBUG_SESSION_SELECTION
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Session %X selected: Using last session used to send to forced address \n", pc->last_session);
+#endif
+ return pc->last_session;
+ }
+ }
+ }
+ /* find session in existing sessions */
+ tmp = pc->head;
+ while ((tmp!=NULL) && (addr_given == GNUNET_YES))
+ {
+
+ if (0 == memcmp(tmp->addr, addr, addrlen))
+ {
+ /* connection can not be used, since it is disconnected */
+ if ((tmp->recv_force_disconnect==GNUNET_NO) && (tmp->send_force_disconnect==GNUNET_NO))
+ {
+#if DEBUG_SESSION_SELECTION
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Session %X selected: Using existing session to send to forced address \n", session);
+#endif
+ return session;
+ }
+
+ }
+ tmp=tmp->next;
+ }
+ /* no session to use */
+ return NULL;
+ }
+ if ((force_address == GNUNET_NO) || (force_address == GNUNET_SYSERR))
+ {
+ /* check session given as argument */
+ if (session != NULL)
+ {
+ /* connection can not be used, since it is disconnected */
+ if ((session->recv_force_disconnect==GNUNET_NO) && (session->send_force_disconnect==GNUNET_NO))
+ {
+#if DEBUG_SESSION_SELECTION
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Session %X selected: Using session passed by transport to send not-forced address \n", session);
+#endif
+ return session;
+ }
+
+ }
+ /* check last session used */
+ if (pc->last_session != NULL)
+ {
+ /* connection can not be used, since it is disconnected */
+ if ((pc->last_session->recv_force_disconnect==GNUNET_NO) && (pc->last_session->send_force_disconnect==GNUNET_NO))
+ {
+#if DEBUG_SESSION_SELECTION
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Session %X selected: Using last session to send to not-forced address \n", pc->last_session);
+#endif
+ return pc->last_session;
+ }
+ }
+ /* find session in existing sessions */
+ tmp = pc->head;
+ while (tmp!=NULL)
+ {
+ /* connection can not be used, since it is disconnected */
+ if ((tmp->recv_force_disconnect==GNUNET_NO) && (tmp->send_force_disconnect==GNUNET_NO))
+ {
+#if DEBUG_SESSION_SELECTION
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Session %X selected: Using existing session to send to not-forced address \n", tmp);
+#endif
+ return tmp;
+ }
+ tmp=tmp->next;
+ }
+ return NULL;
+ }
+ return NULL;
+}