mirror of
https://git.jabber.space/devs/cproof.git
synced 2026-08-02 14:16:22 +00:00
handle see-other-host XMPP stream error
Fixes #1628 Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
This commit is contained in:
@@ -872,6 +872,70 @@ connection_set_priority(const int priority)
|
|||||||
conn.priority = priority;
|
conn.priority = priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(LIBXMPP_VERSION_MAJOR) && defined(LIBXMPP_VERSION_MINOR) \
|
||||||
|
&& ((LIBXMPP_VERSION_MAJOR > 0) || (LIBXMPP_VERSION_MINOR >= 12))
|
||||||
|
static xmpp_stanza_t*
|
||||||
|
_get_soh_error(xmpp_stanza_t* error_stanza)
|
||||||
|
{
|
||||||
|
return xmpp_stanza_get_child_by_path(error_stanza,
|
||||||
|
XMPP_STANZA_NAME_IN_NS("error", STANZA_NS_STREAMS),
|
||||||
|
XMPP_STANZA_NAME_IN_NS("see-other-host", STANZA_NS_XMPP_STREAMS),
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static xmpp_stanza_t*
|
||||||
|
_get_soh_error(xmpp_stanza_t* error_stanza)
|
||||||
|
{
|
||||||
|
const char* name = xmpp_stanza_get_name(error_stanza);
|
||||||
|
const char* ns = xmpp_stanza_get_ns(error_stanza);
|
||||||
|
if (!name || !ns || strcmp(name, "error") || strcmp(ns, STANZA_NS_STREAMS)) {
|
||||||
|
log_debug("_get_soh_error: could not find error stanza");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return xmpp_stanza_get_child_by_name_and_ns(error_stanza, "see-other-host", STANZA_NS_XMPP_STREAMS);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static bool
|
||||||
|
_get_other_host(xmpp_stanza_t* error_stanza, gchar** host, int* port)
|
||||||
|
{
|
||||||
|
xmpp_stanza_t* soh_error = _get_soh_error(error_stanza);
|
||||||
|
if (!soh_error || !xmpp_stanza_get_children(soh_error)) {
|
||||||
|
log_debug("_get_other_host: stream-error contains no see-other-host");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const char* alturi = xmpp_stanza_get_text_ptr(xmpp_stanza_get_children(soh_error));
|
||||||
|
if (!alturi) {
|
||||||
|
log_debug("_get_other_host: see-other-host contains no text");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* Construct a valid URI with `schema://` as `g_uri_split_network()`
|
||||||
|
* requires this to be there.
|
||||||
|
*/
|
||||||
|
const char* xmpp = "xmpp://";
|
||||||
|
char* xmpp_uri = malloc(strlen(xmpp) + strlen(alturi) + 1);
|
||||||
|
if (!xmpp_uri) {
|
||||||
|
log_debug("_get_other_host: malloc failed \"%s\"", alturi);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(xmpp_uri, xmpp, strlen(xmpp));
|
||||||
|
memcpy(xmpp_uri + strlen(xmpp), alturi, strlen(alturi) + 1);
|
||||||
|
|
||||||
|
if (!g_uri_split_network(xmpp_uri, 0, NULL, host, port, NULL)) {
|
||||||
|
log_debug("_get_other_host: Could not split \"%s\"", xmpp_uri);
|
||||||
|
free(xmpp_uri);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
free(xmpp_uri);
|
||||||
|
/* fix-up `port` as g_uri_split_network() sets port to `-1` if it's missing
|
||||||
|
* in the passed-in URI, but libstrophe expects a "missing port"
|
||||||
|
* to be passed as `0` (which then results in connecting to the standard port).
|
||||||
|
*/
|
||||||
|
if (*port == -1)
|
||||||
|
*port = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_connection_handler(xmpp_conn_t* const xmpp_conn, const xmpp_conn_event_t status, const int error,
|
_connection_handler(xmpp_conn_t* const xmpp_conn, const xmpp_conn_event_t status, const int error,
|
||||||
xmpp_stream_error_t* const stream_error, void* const userdata)
|
xmpp_stream_error_t* const stream_error, void* const userdata)
|
||||||
@@ -924,6 +988,14 @@ _connection_handler(xmpp_conn_t* const xmpp_conn, const xmpp_conn_event_t status
|
|||||||
|
|
||||||
// login attempt failed
|
// login attempt failed
|
||||||
} else if (conn.conn_status != JABBER_DISCONNECTING) {
|
} else if (conn.conn_status != JABBER_DISCONNECTING) {
|
||||||
|
gchar* host;
|
||||||
|
int port;
|
||||||
|
if (stream_error && stream_error->stanza && _get_other_host(stream_error->stanza, &host, &port)) {
|
||||||
|
session_reconnect(host, port);
|
||||||
|
log_debug("Connection handler: Forcing a re-connect to \"%s\"", host);
|
||||||
|
conn.conn_status = JABBER_RECONNECT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
log_debug("Connection handler: Login failed");
|
log_debug("Connection handler: Login failed");
|
||||||
session_login_failed();
|
session_login_failed();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -272,6 +272,9 @@ session_process_events(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case JABBER_RECONNECT:
|
||||||
|
_session_reconnect();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -532,6 +535,24 @@ session_check_autoaway(void)
|
|||||||
g_free(mode);
|
g_free(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
gchar* altdomain;
|
||||||
|
unsigned short altport;
|
||||||
|
} reconnect;
|
||||||
|
|
||||||
|
/* This takes ownership of `altdomain`, i.e. the caller must not
|
||||||
|
* free the value after calling this function.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
session_reconnect(gchar* altdomain, unsigned short altport)
|
||||||
|
{
|
||||||
|
reconnect.altdomain = altdomain;
|
||||||
|
reconnect.altport = altport;
|
||||||
|
assert(reconnect_timer == NULL);
|
||||||
|
reconnect_timer = g_timer_new();
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_session_reconnect(void)
|
_session_reconnect(void)
|
||||||
{
|
{
|
||||||
@@ -548,9 +569,18 @@ _session_reconnect(void)
|
|||||||
} else {
|
} else {
|
||||||
jid = strdup(account->jid);
|
jid = strdup(account->jid);
|
||||||
}
|
}
|
||||||
|
const char* server;
|
||||||
|
unsigned short port;
|
||||||
|
if (reconnect.altdomain) {
|
||||||
|
server = reconnect.altdomain;
|
||||||
|
port = reconnect.altport;
|
||||||
|
} else {
|
||||||
|
server = account->server;
|
||||||
|
port = account->port;
|
||||||
|
}
|
||||||
|
|
||||||
log_debug("Attempting reconnect with account %s", account->name);
|
log_debug("Attempting reconnect with account %s", account->name);
|
||||||
connection_connect(jid, saved_account.passwd, account->server, account->port, account->tls_policy, account->auth_policy);
|
connection_connect(jid, saved_account.passwd, server, port, account->tls_policy, account->auth_policy);
|
||||||
free(jid);
|
free(jid);
|
||||||
account_free(account);
|
account_free(account);
|
||||||
g_timer_start(reconnect_timer);
|
g_timer_start(reconnect_timer);
|
||||||
@@ -561,6 +591,7 @@ _session_free_internals(void)
|
|||||||
{
|
{
|
||||||
FREE_SET_NULL(saved_account.name);
|
FREE_SET_NULL(saved_account.name);
|
||||||
FREE_SET_NULL(saved_account.passwd);
|
FREE_SET_NULL(saved_account.passwd);
|
||||||
|
GFREE_SET_NULL(reconnect.altdomain);
|
||||||
_session_free_saved_details();
|
_session_free_saved_details();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,4 +46,6 @@ void session_autoping_fail(void);
|
|||||||
void session_init_activity(void);
|
void session_init_activity(void);
|
||||||
void session_check_autoaway(void);
|
void session_check_autoaway(void);
|
||||||
|
|
||||||
|
void session_reconnect(gchar* altdomain, unsigned short altport);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -245,6 +245,8 @@
|
|||||||
#define STANZA_NS_REPORTING "urn:xmpp:reporting:1"
|
#define STANZA_NS_REPORTING "urn:xmpp:reporting:1"
|
||||||
#define STANZA_NS_MOOD "http://jabber.org/protocol/mood"
|
#define STANZA_NS_MOOD "http://jabber.org/protocol/mood"
|
||||||
#define STANZA_NS_MOOD_NOTIFY "http://jabber.org/protocol/mood+notify"
|
#define STANZA_NS_MOOD_NOTIFY "http://jabber.org/protocol/mood+notify"
|
||||||
|
#define STANZA_NS_STREAMS "http://etherx.jabber.org/streams"
|
||||||
|
#define STANZA_NS_XMPP_STREAMS "urn:ietf:params:xml:ns:xmpp-streams"
|
||||||
|
|
||||||
#define STANZA_DATAFORM_SOFTWARE "urn:xmpp:dataforms:softwareinfo"
|
#define STANZA_DATAFORM_SOFTWARE "urn:xmpp:dataforms:softwareinfo"
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,8 @@ typedef enum {
|
|||||||
JABBER_DISCONNECTING,
|
JABBER_DISCONNECTING,
|
||||||
JABBER_DISCONNECTED,
|
JABBER_DISCONNECTED,
|
||||||
JABBER_RAW_CONNECTING,
|
JABBER_RAW_CONNECTING,
|
||||||
JABBER_RAW_CONNECTED
|
JABBER_RAW_CONNECTED,
|
||||||
|
JABBER_RECONNECT
|
||||||
} jabber_conn_status_t;
|
} jabber_conn_status_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|||||||
Reference in New Issue
Block a user