summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Alan Fitton <ajf@eth0.org.uk>2011-09-11 10:27:06 +0000
committerGravatar Alan Fitton <ajf@eth0.org.uk>2011-09-11 10:27:06 +0000
commitbe569c0953fcd777ae00ae41feb9c673e4df2f23 (patch)
treede0c822ae4ca82e5a717a04a11271f6d544c6507 /src
parent547bcd3c5ec89e30f20723b46c8eab1a71e0cf44 (diff)
use thread local storage to keep one curl client per thread (by default 3) in the thread pool
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am3
-rw-r--r--src/dispatch.c14
-rw-r--r--src/dispatch.h2
-rw-r--r--src/http.c158
-rw-r--r--src/http.h43
-rw-r--r--src/json.c5
-rw-r--r--src/json.h4
-rw-r--r--src/main.c1
-rw-r--r--src/protocol-constants.h5
-rw-r--r--src/torrent.c6
-rw-r--r--src/trg-client.c172
-rw-r--r--src/trg-client.h33
-rw-r--r--src/trg-general-panel.c4
-rw-r--r--src/trg-main-window.c40
-rw-r--r--src/trg-trackers-tree-view.c1
15 files changed, 253 insertions, 238 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 3339143..49da641 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -26,14 +26,13 @@ transmission_remote_gtk_SOURCES = main.c \
requests.c \
base64.c \
json.c \
- http.c \
- dispatch.c \
trg-main-window.c \
util.c \
trg-about-window.c \
torrent.c \
tpeer.c \
tfile.c \
+ dispatch.c \
session-get.c \
trg-client.c \
trg-preferences-dialog.c \
diff --git a/src/dispatch.c b/src/dispatch.c
index e6181a1..e92cb34 100644
--- a/src/dispatch.c
+++ b/src/dispatch.c
@@ -24,8 +24,8 @@
#include "config.h"
#include "dispatch.h"
-#include "http.h"
#include "json.h"
+#include "protocol-constants.h"
static void dispatch_async_threadfunc(struct DispatchAsyncData *task,
TrgClient * client);
@@ -33,7 +33,7 @@ static void dispatch_async_threadfunc(struct DispatchAsyncData *task,
JsonObject *dispatch(TrgClient * client, JsonNode * req, int *status)
{
gchar *serialized;
- struct http_response *response;
+ trg_http_response *response;
JsonObject *deserialized;
JsonNode *result;
GError *decode_error = NULL;
@@ -42,7 +42,7 @@ JsonObject *dispatch(TrgClient * client, JsonNode * req, int *status)
json_node_free(req);
#ifdef DEBUG
if (g_getenv("TRG_SHOW_OUTGOING"))
- g_debug("=>(outgoing)=>\n%s\n", serialized);
+ g_debug("=>(outgoing)=>\n%s", serialized);
#endif
response = trg_http_perform(client, serialized);
g_free(serialized);
@@ -59,16 +59,16 @@ JsonObject *dispatch(TrgClient * client, JsonNode * req, int *status)
http_response_free(response);
if (decode_error) {
- g_printf("JSON decoding error: %s\n", decode_error->message);
+ g_error("JSON decoding error: %s", decode_error->message);
g_error_free(decode_error);
if (status)
*status = FAIL_JSON_DECODE;
return NULL;
}
- result = json_object_get_member(deserialized, "result");
+ result = json_object_get_member(deserialized, FIELD_RESULT);
if (status
- && (!result || g_strcmp0(json_node_get_string(result), "success")))
+ && (!result || g_strcmp0(json_node_get_string(result), FIELD_SUCCESS)))
*status = FAIL_RESPONSE_UNSUCCESSFUL;
return deserialized;
@@ -87,7 +87,7 @@ static void dispatch_async_threadfunc(struct DispatchAsyncData *task,
GThreadPool *dispatch_init_pool(TrgClient * client)
{
return g_thread_pool_new((GFunc) dispatch_async_threadfunc, client,
- DISPATCH_POOL_SIZE, FALSE, NULL);
+ DISPATCH_POOL_SIZE, TRUE, NULL);
}
gboolean dispatch_async(TrgClient * client, JsonNode * req,
diff --git a/src/dispatch.h b/src/dispatch.h
index 6734f33..0e7225f 100644
--- a/src/dispatch.h
+++ b/src/dispatch.h
@@ -25,7 +25,7 @@
#define FAIL_JSON_DECODE -2
#define FAIL_RESPONSE_UNSUCCESSFUL -3
-#define DISPATCH_POOL_SIZE 4
+#define DISPATCH_POOL_SIZE 3
struct DispatchAsyncData {
gpointer *data;
diff --git a/src/http.c b/src/http.c
deleted file mode 100644
index ddbe413..0000000
--- a/src/http.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * transmission-remote-gtk - A GTK RPC client to Transmission
- * Copyright (C) 2011 Alan Fitton
-
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <curl/curl.h>
-#include <curl/easy.h>
-
-#include <glib-object.h>
-#include <json-glib/json-glib.h>
-
-#include "trg-client.h"
-#include "http.h"
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-static struct http_response *trg_http_perform_inner(TrgClient * client,
- gchar * req,
- gboolean recurse);
-
-static size_t http_receive_callback(void *ptr, size_t size, size_t nmemb,
- void *data);
-
-static size_t header_callback(void *ptr, size_t size, size_t nmemb,
- void *data);
-
-void http_response_free(struct http_response *response)
-{
- if (response->data != NULL)
- g_free(response->data);
-
- g_free(response);
-}
-
-static struct http_response *trg_http_perform_inner(TrgClient * tc,
- gchar * req,
- gboolean recurse)
-{
- CURL *handle;
- long httpCode;
- struct http_response *response;
- struct curl_slist *headers = NULL;
- gchar *proxy, *session_id;
-
- response = g_new(struct http_response, 1);
- response->size = 0;
- response->status = -1;
- response->data = NULL;
-
- handle = curl_easy_init();
-
- curl_easy_setopt(handle, CURLOPT_USERAGENT, PACKAGE_NAME);
- curl_easy_setopt(handle, CURLOPT_PASSWORD, trg_client_get_password(tc));
- curl_easy_setopt(handle, CURLOPT_USERNAME, trg_client_get_username(tc));
- curl_easy_setopt(handle, CURLOPT_URL, trg_client_get_url(tc));
- curl_easy_setopt(handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
- curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION,
- &http_receive_callback);
- curl_easy_setopt(handle, CURLOPT_WRITEDATA, (void *) response);
- curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, &header_callback);
- curl_easy_setopt(handle, CURLOPT_WRITEHEADER, (void *) tc);
- curl_easy_setopt(handle, CURLOPT_POSTFIELDS, req);
-
-
- if (trg_client_get_ssl(tc))
- curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0);
-
- proxy = trg_client_get_proxy(tc);
- if (proxy) {
- curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
- curl_easy_setopt(handle, CURLOPT_PROXY, proxy);
- }
-
- session_id = trg_client_get_session_id(tc);
- if (session_id) {
- headers = curl_slist_append(headers, session_id);
- curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
- }
-
- response->status = curl_easy_perform(handle);
-
- curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &httpCode);
- curl_easy_cleanup(handle);
-
- if (headers)
- curl_slist_free_all(headers);
-
- if (response->status == CURLE_OK) {
- if (httpCode == HTTP_CONFLICT && recurse == TRUE) {
- http_response_free(response);
- return trg_http_perform_inner(tc, req, FALSE);
- } else if (httpCode != HTTP_OK) {
- response->status = (-httpCode) - 100;
- }
- }
-
- return response;
-}
-
-struct http_response *trg_http_perform(TrgClient * tc, gchar * req)
-{
- return trg_http_perform_inner(tc, req, TRUE);
-}
-
-static size_t
-http_receive_callback(void *ptr, size_t size, size_t nmemb, void *data)
-{
- size_t realsize = size * nmemb;
- struct http_response *mem = (struct http_response *) data;
-
- mem->data = realloc(mem->data, mem->size + realsize + 1);
- if (mem->data) {
- memcpy(&(mem->data[mem->size]), ptr, realsize);
- mem->size += realsize;
- mem->data[mem->size] = 0;
- }
- return realsize;
-}
-
-static size_t header_callback(void *ptr, size_t size, size_t nmemb,
- void *data)
-{
- char *header = (char *) (ptr);
- TrgClient *tc = TRG_CLIENT(data);
- gchar *session_id;
-
- if (g_str_has_prefix(header, "X-Transmission-Session-Id: ")) {
- char *nl;
-
- session_id = g_strdup(header);
- nl = strrchr(session_id, '\r');
- if (nl)
- *nl = '\0';
-
- trg_client_set_session_id(tc, session_id);
- }
-
- return (nmemb * size);
-}
diff --git a/src/http.h b/src/http.h
deleted file mode 100644
index 6fe9783..0000000
--- a/src/http.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * transmission-remote-gtk - A GTK RPC client to Transmission
- * Copyright (C) 2011 Alan Fitton
-
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef HTTP_H_
-#define HTTP_H_
-
-#include <stdlib.h>
-
-#include <glib-object.h>
-#include <json-glib/json-glib.h>
-#include <curl/curl.h>
-
-#include "trg-client.h"
-
-#define HTTP_OK 200
-#define HTTP_CONFLICT 409
-
-struct http_response {
- int status;
- char *data;
- int size;
-};
-
-void http_response_free(struct http_response *response);
-struct http_response *trg_http_perform(TrgClient * client, gchar * req);
-
-#endif /* HTTP_H_ */
diff --git a/src/json.c b/src/json.c
index 47ca27b..6d74b24 100644
--- a/src/json.c
+++ b/src/json.c
@@ -26,7 +26,6 @@
#include "protocol-constants.h"
#include "requests.h"
#include "dispatch.h"
-#include "http.h"
#include "json.h"
gchar *trg_serialize(JsonNode * req)
@@ -44,7 +43,7 @@ gchar *trg_serialize(JsonNode * req)
return response;
}
-JsonObject *trg_deserialize(struct http_response * response,
+JsonObject *trg_deserialize(trg_http_response * response,
GError ** error)
{
JsonParser *parser;
@@ -58,7 +57,7 @@ JsonObject *trg_deserialize(struct http_response * response,
root = json_parser_get_root(parser);
#ifdef DEBUG
if (g_getenv("TRG_SHOW_INCOMING") != NULL) {
- g_debug("<=(incoming)<=:\n%s\n", response->data);
+ g_debug("<=(incoming)<=:\n%s", response->data);
} else if (g_getenv("TRG_SHOW_INCOMING_PRETTY") != NULL) {
JsonGenerator *pg;
gsize len;
diff --git a/src/json.h b/src/json.h
index 1234784..a71e130 100644
--- a/src/json.h
+++ b/src/json.h
@@ -23,10 +23,10 @@
#include <glib-object.h>
#include <json-glib/json-glib.h>
-#include "http.h"
+#include "trg-client.h"
gchar *trg_serialize(JsonNode * req);
-JsonObject *trg_deserialize(struct http_response *response,
+JsonObject *trg_deserialize(trg_http_response *response,
GError ** error);
JsonObject *get_arguments(JsonObject * req);
JsonObject *node_get_arguments(JsonNode * req);
diff --git a/src/main.c b/src/main.c
index fb54202..3530b8c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -34,7 +34,6 @@
#include <unique/unique.h>
#endif
-#include "http.h"
#include "trg-main-window.h"
#include "trg-client.h"
diff --git a/src/protocol-constants.h b/src/protocol-constants.h
index 01fd99e..ccc91c4 100644
--- a/src/protocol-constants.h
+++ b/src/protocol-constants.h
@@ -25,6 +25,11 @@
#define PARAM_METHOD "method"
#define FIELD_ID "id"
+/* top level */
+
+#define FIELD_RESULT "result"
+#define FIELD_SUCCESS "success"
+
/* torrents */
#define FIELD_RECENTLY_ACTIVE "recently-active"
diff --git a/src/torrent.c b/src/torrent.c
index 85b351b..73fa66a 100644
--- a/src/torrent.c
+++ b/src/torrent.c
@@ -315,9 +315,11 @@ gchar *torrent_get_status_string(gint64 rpcv, gint64 value)
gboolean torrent_has_tracker(JsonObject * t, GRegex * rx, gchar * search)
{
- GList *trackers = json_array_get_elements(torrent_get_tracker_stats(t));
- gboolean ret = FALSE;
+ GList *trackers;
GList *li;
+ gboolean ret = FALSE;
+
+ trackers = json_array_get_elements(torrent_get_tracker_stats(t));
for (li = trackers; li; li = g_list_next(li)) {
JsonObject *tracker = json_node_get_object((JsonNode *) li->data);
diff --git a/src/trg-client.c b/src/trg-client.c
index 44943ea..6810278 100644
--- a/src/trg-client.c
+++ b/src/trg-client.c
@@ -21,6 +21,7 @@
#include "config.h"
#endif
+#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <glib/gprintf.h>
@@ -29,6 +30,9 @@
#include <proxy.h>
#endif
+#include <curl/curl.h>
+#include <curl/easy.h>
+
#include "trg-prefs.h"
#include "util.h"
#include "dispatch.h"
@@ -66,6 +70,9 @@ struct _TrgClientPrivate {
GThreadPool *pool;
GMutex *updateMutex;
TrgPrefs *prefs;
+ GPrivate *tlsKey;
+ gint configSerial;
+ GMutex *configMutex;
};
static void
@@ -130,10 +137,10 @@ trg_client_new (void)
trg_prefs_load(prefs);
priv->updateMutex = g_mutex_new();
- priv->activeOnlyUpdate =
- trg_prefs_get_bool(prefs,
- TRG_PREFS_KEY_UPDATE_ACTIVE_ONLY, TRG_PREFS_PROFILE);
+ priv->configMutex = g_mutex_new();
+ priv->configSerial = 0;
priv->pool = dispatch_init_pool(tc);
+ priv->tlsKey = g_private_new(NULL);
return tc;
}
@@ -181,6 +188,8 @@ int trg_client_populate_with_settings(TrgClient * tc)
pxProxyFactory *pf = NULL;
#endif
+ g_mutex_lock(priv->configMutex);
+
g_free(priv->url);
priv->url = NULL;
@@ -227,6 +236,10 @@ int trg_client_populate_with_settings(TrgClient * tc)
g_free(priv->proxy);
priv->proxy = NULL;
+ priv->activeOnlyUpdate =
+ trg_prefs_get_bool(prefs,
+ TRG_PREFS_KEY_UPDATE_ACTIVE_ONLY, TRG_PREFS_PROFILE);
+
#ifdef HAVE_LIBPROXY
if ((pf = px_proxy_factory_new())) {
char **proxies = px_proxy_factory_get_proxies(pf, priv->url);
@@ -246,6 +259,8 @@ int trg_client_populate_with_settings(TrgClient * tc)
}
#endif
+ priv->configSerial++;
+ g_mutex_unlock(priv->configMutex);
return 0;
}
@@ -270,17 +285,21 @@ gchar *trg_client_get_url(TrgClient *tc)
gchar *trg_client_get_session_id(TrgClient *tc)
{
TrgClientPrivate *priv = TRG_CLIENT_GET_PRIVATE(tc);
- return priv->session_id;
+ return priv->session_id ? g_strdup(priv->session_id) : NULL;
}
void trg_client_set_session_id(TrgClient *tc, gchar *session_id)
{
TrgClientPrivate *priv = TRG_CLIENT_GET_PRIVATE(tc);
+ g_mutex_lock(priv->configMutex);
+
if (priv->session_id)
g_free(priv->session_id);
priv->session_id = session_id;
+
+ g_mutex_unlock(priv->configMutex);
}
void trg_client_status_change(TrgClient *tc, gboolean connected)
@@ -411,3 +430,148 @@ void trg_client_set_minimised_interval(TrgClient *tc, guint interval)
TrgClientPrivate *priv = TRG_CLIENT_GET_PRIVATE(tc);
priv->min_interval = interval;
}
+
+/* formerly http.c */
+
+void http_response_free(trg_http_response *response)
+{
+ g_free(response->data);
+ response->data = NULL;
+}
+
+static size_t
+http_receive_callback(void *ptr, size_t size, size_t nmemb, void *data)
+{
+ size_t realsize = size * nmemb;
+ trg_http_response *mem = (trg_http_response *) data;
+
+ mem->data = realloc(mem->data, mem->size + realsize + 1);
+ if (mem->data) {
+ memcpy(&(mem->data[mem->size]), ptr, realsize);
+ mem->size += realsize;
+ mem->data[mem->size] = 0;
+ }
+ return realsize;
+}
+
+static size_t header_callback(void *ptr, size_t size, size_t nmemb,
+ void *data)
+{
+ char *header = (char *) (ptr);
+ TrgClient *tc = TRG_CLIENT(data);
+ gchar *session_id;
+
+ if (g_str_has_prefix(header, X_TRANSMISSION_SESSION_ID_HEADER_PREFIX)) {
+ char *nl;
+
+ session_id = g_strdup(header);
+ nl = strrchr(session_id, '\r');
+ if (nl)
+ *nl = '\0';
+
+ trg_client_set_session_id(tc, session_id);
+ }
+
+ return (nmemb * size);
+}
+
+static void trg_tls_update(TrgClient *tc, trg_tls *tls, gint serial)
+{
+ gchar *proxy;
+
+ curl_easy_setopt(tls->curl, CURLOPT_PASSWORD, trg_client_get_password(tc));
+ curl_easy_setopt(tls->curl, CURLOPT_USERNAME, trg_client_get_username(tc));
+ curl_easy_setopt(tls->curl, CURLOPT_URL, trg_client_get_url(tc));
+
+ if (trg_client_get_ssl(tc))
+ curl_easy_setopt(tls->curl, CURLOPT_SSL_VERIFYPEER, 0);
+
+ proxy = trg_client_get_proxy(tc);
+ if (proxy) {
+ curl_easy_setopt(tls->curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
+ curl_easy_setopt(tls->curl, CURLOPT_PROXY, proxy);
+ }
+
+ tls->serial = serial;
+}
+
+trg_tls *trg_tls_new(TrgClient *tc)
+{
+ trg_tls *tls = g_new0(trg_tls, 1);
+
+ tls->response = g_new0(trg_http_response, 1);
+
+ tls->curl = curl_easy_init();
+ curl_easy_setopt(tls->curl, CURLOPT_USERAGENT, PACKAGE_NAME);
+ curl_easy_setopt(tls->curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
+ curl_easy_setopt(tls->curl, CURLOPT_WRITEFUNCTION,
+ &http_receive_callback);
+ curl_easy_setopt(tls->curl, CURLOPT_WRITEDATA, (void *)tls->response);
+ curl_easy_setopt(tls->curl, CURLOPT_HEADERFUNCTION, &header_callback);
+ curl_easy_setopt(tls->curl, CURLOPT_WRITEHEADER, (void *) tc);
+
+ tls->serial = -1;
+
+ return tls;
+}
+
+static trg_http_response *trg_http_perform_inner(TrgClient * tc,
+ gchar * req,
+ gboolean recurse)
+{
+ TrgClientPrivate *priv = TRG_CLIENT_GET_PRIVATE(tc);
+ gpointer threadLocalStorage = g_private_get(priv->tlsKey);
+ trg_tls *tls;
+ long httpCode = 0;
+ gchar *session_id;
+ struct curl_slist *headers = NULL;
+
+ if (!threadLocalStorage) {
+ tls = trg_tls_new(tc);
+ g_private_set(priv->tlsKey, tls);
+ } else {
+ tls = (trg_tls*)threadLocalStorage;
+ }
+
+ g_mutex_lock(priv->configMutex);
+
+ if (priv->configSerial > tls->serial)
+ trg_tls_update(tc, tls, priv->configSerial);
+
+ session_id = trg_client_get_session_id(tc);
+ if (session_id) {
+ headers = curl_slist_append(NULL, session_id);
+ curl_easy_setopt(tls->curl, CURLOPT_HTTPHEADER, headers);
+ }
+
+ g_mutex_unlock(priv->configMutex);
+
+ tls->response->size = 0;
+ tls->response->status = -1;
+ g_free(tls->response->data);
+ tls->response->data = NULL;
+
+ curl_easy_setopt(tls->curl, CURLOPT_POSTFIELDS, req);
+ tls->response->status = curl_easy_perform(tls->curl);
+
+ if (session_id) {
+ g_free(session_id);
+ curl_slist_free_all(headers);
+ }
+
+ curl_easy_getinfo(tls->curl, CURLINFO_RESPONSE_CODE, &httpCode);
+
+ if (tls->response->status == CURLE_OK) {
+ if (httpCode == HTTP_CONFLICT && recurse == TRUE)
+ return trg_http_perform_inner(tc, req, FALSE);
+ else if (httpCode != HTTP_OK)
+ tls->response->status = (-httpCode) - 100;
+ }
+
+ return tls->response;
+}
+
+trg_http_response *trg_http_perform(TrgClient * tc, gchar * req)
+{
+ return trg_http_perform_inner(tc, req, TRUE);
+}
diff --git a/src/trg-client.h b/src/trg-client.h
index 67d026b..78a674d 100644
--- a/src/trg-client.h
+++ b/src/trg-client.h
@@ -16,12 +16,14 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+
/* trg-client.h */
#ifndef _TRG_CLIENT_H_
#define _TRG_CLIENT_H_
#define TRANSMISSION_MIN_SUPPORTED 2.0
+#define X_TRANSMISSION_SESSION_ID_HEADER_PREFIX "X-Transmission-Session-Id: "
#define TRG_MAX_RETRIES 3
#define TORRENT_GET_MODE_FIRST 0
@@ -32,12 +34,24 @@
#define TRG_NO_HOSTNAME_SET -2
#define SESSION_UPDATE_DIVISOR 10
+#include <curl/curl.h>
+#include <curl/easy.h>
+
#include <json-glib/json-glib.h>
#include <glib-object.h>
#include "trg-prefs.h"
#include "session-get.h"
+#define HTTP_OK 200
+#define HTTP_CONFLICT 409
+
+typedef struct {
+ int status;
+ char *data;
+ int size;
+} trg_http_response;
+
G_BEGIN_DECLS
#define TRG_TYPE_CLIENT trg_client_get_type()
@@ -67,6 +81,25 @@ typedef struct {
} TrgClientClass;
+/* Thread local storage (TLS).
+ * CURL clients can't be used concurrently.
+ * So create one instance for each thread in the thread pool.
+ */
+typedef struct {
+ /* Use a serial to figure out when there's been a configuration change
+ * by comparing with priv->serial.
+ * We lock updating (and checking for updates) with priv->configMutex
+ */
+ int serial;
+ CURL *curl;
+ trg_http_response *response;
+} trg_tls;
+
+/* stuff that used to be in http.h */
+void http_response_free(trg_http_response *response);
+trg_http_response *trg_http_perform(TrgClient * client, gchar * req);
+/* end http.h*/
+
GType trg_client_get_type (void);
TrgClient* trg_client_new (void);
diff --git a/src/trg-general-panel.c b/src/trg-general-panel.c
index 0cdff84..0c7742e 100644
--- a/src/trg-general-panel.c
+++ b/src/trg-general-panel.c
@@ -190,9 +190,9 @@ void trg_general_panel_update(TrgGeneralPanel * panel, JsonObject * t,
TORRENT_COLUMN_SEEDS, &seeders,
TORRENT_COLUMN_LEECHERS, &leechers, -1);
- snprintf(buf, sizeof(buf), "%d", seeders);
+ snprintf(buf, sizeof(buf), "%d", seeders >= 0 ? seeders : 0);
gtk_label_set_text(GTK_LABEL(priv->gen_seeders_label), buf);
- snprintf(buf, sizeof(buf), "%d", leechers);
+ snprintf(buf, sizeof(buf), "%d", leechers >= 0 ? leechers : 0);
gtk_label_set_text(GTK_LABEL(priv->gen_leechers_label), buf);
}
diff --git a/src/trg-main-window.c b/src/trg-main-window.c
index 48e7c4b..972ba2d 100644
--- a/src/trg-main-window.c
+++ b/src/trg-main-window.c
@@ -36,7 +36,6 @@
#include "dispatch.h"
#include "trg-client.h"
-#include "http.h"
#include "json.h"
#include "util.h"
#include "requests.h"
@@ -737,6 +736,7 @@ static void on_session_get(JsonObject * response, int status, gpointer data) {
TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(data);
TrgClient *client = priv->client;
JsonObject *newSession;
+ gboolean isConnected = trg_client_is_connected(client);
gdk_threads_enter();
@@ -748,7 +748,7 @@ static void on_session_get(JsonObject * response, int status, gpointer data) {
newSession = get_arguments(response);
- if (!trg_client_is_connected(client)) {
+ if (!isConnected) {
float version;
if (session_get_version(newSession, &version)) {
if (version < TRANSMISSION_MIN_SUPPORTED) {
@@ -765,21 +765,31 @@ static void on_session_get(JsonObject * response, int status, gpointer data) {
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
g_free(msg);
- goto out;
+ gdk_threads_leave();
+ response_unref(response);
+ return;
}
}
trg_status_bar_connect(priv->statusBar, newSession);
trg_main_window_conn_changed(win, TRUE);
- dispatch_async(client, torrent_get(-1), on_torrent_get_first, data);
}
trg_client_set_session(client, newSession);
- trg_trackers_tree_view_new_connection(priv->trackersTreeView, client);
+
+ if (!isConnected)
+ trg_trackers_tree_view_new_connection(priv->trackersTreeView, client);
+
+ gdk_threads_leave();
json_object_ref(newSession);
- out: gdk_threads_leave();
response_unref(response);
+
+ if (!isConnected) {
+ int firstStatus;
+ JsonObject *firstResponse = dispatch(client, torrent_get(-1), &firstStatus);
+ on_torrent_get_first(firstResponse, firstStatus, data);
+ }
}
/*
@@ -792,10 +802,7 @@ static void on_torrent_get(JsonObject * response, int mode, int status,
TrgClient *client = priv->client;
trg_torrent_model_update_stats stats;
-
- guint interval =
- gtk_widget_get_visible(GTK_WIDGET(data)) ? trg_client_get_interval(
- client) : trg_client_get_minimised_interval(client);
+ guint interval;
/* Disconnected between request and response callback */
if (!trg_client_is_connected(client)) {
@@ -806,6 +813,9 @@ static void on_torrent_get(JsonObject * response, int mode, int status,
trg_client_updatelock(client);
gdk_threads_enter();
+ interval = gtk_widget_get_visible(GTK_WIDGET(data)) ? trg_client_get_interval(
+ client) : trg_client_get_minimised_interval(client);
+
if (status != CURLE_OK) {
if (trg_client_inc_failcount(client) >= TRG_MAX_RETRIES) {
trg_main_window_conn_changed(TRG_MAIN_WINDOW(data), FALSE);
@@ -923,9 +933,13 @@ static gboolean trg_torrent_tree_view_visible_func(GtkTreeModel * model,
} else if (criteria & FILTER_FLAG_DIR) {
gchar *text = trg_state_selector_get_selected_text(
priv->stateSelector);
- JsonObject *json = NULL;
- gtk_tree_model_get(model, iter, TORRENT_COLUMN_JSON, &json, -1);
- if (g_strcmp0(text, torrent_get_download_dir(json)))
+ gchar *dd;
+ int cmp;
+ gtk_tree_model_get(model, iter, TORRENT_COLUMN_DOWNLOADDIR, &dd, -1);
+ cmp = g_strcmp0(text, dd);
+ g_free(dd);
+ g_free(text);
+ if (cmp)
return FALSE;
} else if (!(flags & criteria)) {
return FALSE;
diff --git a/src/trg-trackers-tree-view.c b/src/trg-trackers-tree-view.c
index 4919bcf..7f385ba 100644
--- a/src/trg-trackers-tree-view.c
+++ b/src/trg-trackers-tree-view.c
@@ -73,6 +73,7 @@ void trg_trackers_tree_view_new_connection(TrgTrackersTreeView * tv,
{
TrgTrackersTreeViewPrivate *priv =
TRG_TRACKERS_TREE_VIEW_GET_PRIVATE(tv);
+
gboolean editable = is_tracker_edit_supported(tc);
g_object_set(priv->announceRenderer, "editable", editable, NULL);