aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordequis <dx@dxzone.com.ar>2015-10-25 01:06:22 -0300
committerdequis <dx@dxzone.com.ar>2015-10-26 00:42:15 -0300
commit4e365cec5275e3dec782af3ec0bc9a651cc2b831 (patch)
tree08382036a53279ac3681ea848e423ebc1881beb7
parentf710673a3d6f7d602c8261789ae78a4f273fb1a9 (diff)
Add proxy_disconnect() to interrupt possibly pending connections
Fixes trac ticket 1198, https://bugs.bitlbee.org/bitlbee/ticket/1198 This function can be used as a safe drop-in replacement to closesocket() If a proxy connection is pending (connected callback still not called), it looks up the PHB in a hash table indexed by fd. If it is there, it closes, frees the phb and avoids further calls to the callback. If it is not in there, it just does closesocket()
-rw-r--r--lib/proxy.c40
-rw-r--r--lib/proxy.h1
2 files changed, 40 insertions, 1 deletions
diff --git a/lib/proxy.c b/lib/proxy.c
index 88649d4e..af30cf4f 100644
--- a/lib/proxy.c
+++ b/lib/proxy.c
@@ -50,6 +50,8 @@ char proxypass[128] = "";
#define AI_ADDRCONFIG 0
#endif
+static GHashTable *phb_hash = NULL;
+
struct PHB {
b_event_handler func, proxy_func;
gpointer data, proxy_data;
@@ -66,6 +68,8 @@ static int proxy_connect_none(const char *host, unsigned short port_, struct PHB
static gboolean phb_free(struct PHB *phb, gboolean success)
{
+ g_hash_table_remove(phb_hash, &phb->fd);
+
if (!success) {
if (phb->fd > 0) {
closesocket(phb->fd);
@@ -99,6 +103,7 @@ static gboolean proxy_connected(gpointer data, gint source, b_input_condition co
closesocket(source);
dup2(new_fd, source);
closesocket(new_fd);
+ phb->fd = source;
phb->inpa = b_input_add(source, B_EV_IO_WRITE, proxy_connected, phb);
return FALSE;
}
@@ -522,6 +527,11 @@ int proxy_connect(const char *host, int port, b_event_handler func, gpointer dat
{
struct PHB *phb;
proxy_connect_func fun;
+ int fd;
+
+ if (!phb_hash) {
+ phb_hash = g_hash_table_new(g_int_hash, g_int_equal);
+ }
if (!host || port <= 0 || !func || strlen(host) > 128) {
return -1;
@@ -537,5 +547,33 @@ int proxy_connect(const char *host, int port, b_event_handler func, gpointer dat
fun = proxy_connect_none;
}
- return fun(host, port, phb);
+ fd = fun(host, port, phb);
+
+ if (fd != -1) {
+ g_hash_table_insert(phb_hash, &phb->fd, phb);
+ }
+
+ return fd;
+}
+
+void proxy_disconnect(int fd)
+{
+ struct PHB *phb = g_hash_table_lookup(phb_hash, &fd);
+
+ if (!phb) {
+ /* not in the early part of the connection - just close the fd */
+ closesocket(fd);
+ return;
+ }
+
+ if (phb->inpa) {
+ b_event_remove(phb->inpa);
+ phb->inpa = 0;
+ }
+
+ /* avoid calling the callback, which might result in double-free */
+ phb->func = NULL;
+
+ /* close and free */
+ phb_free(phb, FALSE);
}
diff --git a/lib/proxy.h b/lib/proxy.h
index eaf31375..3c1b019b 100644
--- a/lib/proxy.h
+++ b/lib/proxy.h
@@ -48,5 +48,6 @@ extern char proxyuser[128];
extern char proxypass[128];
G_MODULE_EXPORT int proxy_connect(const char *host, int port, b_event_handler func, gpointer data);
+G_MODULE_EXPORT void proxy_disconnect(int fd);
#endif /* _PROXY_H_ */