Add API to register callback to set socket options
The registered callback function will be called before connect() is called on the socket, allowing tweaking of much more than just keepalive settings. This deprecates xmpp_conn_set_keepalive(). Includes helper/example callback function to set default keepalive parameters that some library users may find useful.
This commit is contained in:
@@ -174,6 +174,7 @@ struct _xmpp_conn_t {
|
||||
sock_t sock;
|
||||
int ka_timeout; /* TCP keepalive timeout */
|
||||
int ka_interval; /* TCP keepalive interval */
|
||||
int ka_count; /* TCP keepalive count */
|
||||
|
||||
tls_t *tls;
|
||||
int tls_support;
|
||||
@@ -233,6 +234,7 @@ struct _xmpp_conn_t {
|
||||
xmpp_handlist_t *timed_handlers;
|
||||
hash_t *id_handlers;
|
||||
xmpp_handlist_t *handlers;
|
||||
xmpp_sockopt_callback sockopt_cb;
|
||||
};
|
||||
|
||||
void conn_disconnect(xmpp_conn_t *conn);
|
||||
|
||||
77
src/conn.c
77
src/conn.c
@@ -46,11 +46,37 @@
|
||||
#ifndef CONNECT_TIMEOUT
|
||||
/** @def CONNECT_TIMEOUT
|
||||
* The time to wait (in milliseconds) for a connection attempt to succeed
|
||||
* or error. The default is 5 seconds.
|
||||
* or error. The default is 5 seconds.
|
||||
*/
|
||||
#define CONNECT_TIMEOUT 5000 /* 5 seconds */
|
||||
#endif
|
||||
|
||||
#ifndef KEEPALIVE_TIMEOUT
|
||||
/** @def KEEPALIVE_TIMEOUT
|
||||
* The time (in seconds) the connection needs to remain idle before TCP starts
|
||||
* sending keepalive probes, if the socket option SO_KEEPALIVE has been set on
|
||||
* this socket.
|
||||
* c.f. `TCP_KEEPIDLE` in `man 7 tcp` for linux, FreeBSD and some others or
|
||||
* `TCP_KEEPALIVE` on MacOS.
|
||||
*/
|
||||
#define KEEPALIVE_TIMEOUT 60
|
||||
#endif
|
||||
#ifndef KEEPALIVE_INTERVAL
|
||||
/** @def KEEPALIVE_INTERVAL
|
||||
* The time (in seconds) between individual keepalive probes.
|
||||
* c.f. `TCP_KEEPINTVL` in `man 7 tcp`
|
||||
*/
|
||||
#define KEEPALIVE_INTERVAL 30
|
||||
#endif
|
||||
#ifndef KEEPALIVE_COUNT
|
||||
/** @def KEEPALIVE_COUNT
|
||||
* The maximum number of keepalive probes TCP should send before dropping the
|
||||
* connection.
|
||||
* c.f. `TCP_KEEPCNT` in `man 7 tcp`
|
||||
*/
|
||||
#define KEEPALIVE_COUNT 3
|
||||
#endif
|
||||
|
||||
static int _disconnect_cleanup(xmpp_conn_t *conn, void *userdata);
|
||||
static char *_conn_build_stream_tag(xmpp_conn_t *conn,
|
||||
char **attributes,
|
||||
@@ -112,8 +138,9 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx)
|
||||
conn->type = XMPP_UNKNOWN;
|
||||
conn->state = XMPP_STATE_DISCONNECTED;
|
||||
conn->sock = -1;
|
||||
conn->ka_timeout = 0;
|
||||
conn->ka_interval = 0;
|
||||
conn->ka_timeout = KEEPALIVE_TIMEOUT;
|
||||
conn->ka_interval = KEEPALIVE_INTERVAL;
|
||||
conn->ka_count = KEEPALIVE_COUNT;
|
||||
conn->tls = NULL;
|
||||
conn->timeout_stamp = 0;
|
||||
conn->error = 0;
|
||||
@@ -171,6 +198,7 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx)
|
||||
/* we own (and will free) the hash values */
|
||||
conn->id_handlers = hash_new(conn->ctx, 32, NULL);
|
||||
conn->handlers = NULL;
|
||||
conn->sockopt_cb = NULL;
|
||||
|
||||
/* give the caller a reference to connection */
|
||||
conn->ref = 1;
|
||||
@@ -216,33 +244,30 @@ xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t *conn)
|
||||
return conn;
|
||||
}
|
||||
|
||||
/** Set TCP keepalive parameters
|
||||
* Turn on TCP keepalive and set timeout and interval. Zero timeout
|
||||
* disables TCP keepalives. The parameters are applied immediately for
|
||||
* a non disconnected object. Also, they are applied when the connection
|
||||
* object connects successfully.
|
||||
/** Register sockopt callback
|
||||
* Set function to be called when a new socket is created to allow setting
|
||||
* socket options before connection is started.
|
||||
*
|
||||
* @param conn a Strophe connection object
|
||||
* @param timeout TCP keepalive timeout in seconds
|
||||
* @param interval TCP keepalive interval in seconds
|
||||
* If the connection is already connected, this callback will be called
|
||||
* immediately.
|
||||
*
|
||||
* To set options that can only be applied to disconnected sockets, the
|
||||
* callback must be registered before connecting.
|
||||
*
|
||||
* @param conn The Strophe connection object this callback is being registered
|
||||
* for
|
||||
* @param callback a xmpp_sockopt_callback callback function that will receive
|
||||
* notifications of connection status
|
||||
*
|
||||
* @ingroup Connections
|
||||
*/
|
||||
void xmpp_conn_set_keepalive(xmpp_conn_t *conn, int timeout, int interval)
|
||||
|
||||
void xmpp_conn_set_sockopt_callback(xmpp_conn_t *conn,
|
||||
xmpp_sockopt_callback callback)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
conn->ka_timeout = timeout;
|
||||
conn->ka_interval = interval;
|
||||
|
||||
conn->sockopt_cb = callback;
|
||||
if (conn->state != XMPP_STATE_DISCONNECTED)
|
||||
ret = sock_set_keepalive(conn->sock, timeout, interval);
|
||||
|
||||
if (ret < 0) {
|
||||
strophe_error(conn->ctx, "xmpp",
|
||||
"Setting TCP keepalive (%d,%d) error: %d", timeout,
|
||||
interval, sock_error());
|
||||
}
|
||||
callback(conn, &conn->sock);
|
||||
}
|
||||
|
||||
/** Release a Strophe connection object.
|
||||
@@ -1487,13 +1512,11 @@ static int _conn_connect(xmpp_conn_t *conn,
|
||||
if (!conn->domain)
|
||||
return XMPP_EMEM;
|
||||
|
||||
conn->sock = sock_connect(host, port);
|
||||
conn->sock = sock_connect(conn, host, port);
|
||||
strophe_debug(conn->ctx, "xmpp", "sock_connect() to %s:%u returned %d",
|
||||
host, port, conn->sock);
|
||||
if (conn->sock == -1)
|
||||
return XMPP_EINT;
|
||||
if (conn->ka_timeout || conn->ka_interval)
|
||||
sock_set_keepalive(conn->sock, conn->ka_timeout, conn->ka_interval);
|
||||
|
||||
/* setup handler */
|
||||
conn->conn_handler = callback;
|
||||
|
||||
@@ -231,3 +231,26 @@ int xmpp_vsnprintf(char *str, size_t count, const char *fmt, va_list arg)
|
||||
{
|
||||
return strophe_vsnprintf(str, count, fmt, arg);
|
||||
}
|
||||
|
||||
/** Set TCP keepalive parameters
|
||||
* Turn on TCP keepalive and set timeout and interval. Zero timeout
|
||||
* disables TCP keepalives. The parameters are applied immediately for
|
||||
* a non disconnected object. Also, they are applied when the connection
|
||||
* object connects successfully.
|
||||
*
|
||||
* @param conn a Strophe connection object
|
||||
* @param timeout TCP keepalive timeout in seconds
|
||||
* @param interval TCP keepalive interval in seconds
|
||||
*
|
||||
* @note this function is deprecated
|
||||
* @see xmpp_conn_set_sockopt_callback()
|
||||
*
|
||||
* @ingroup Deprecated
|
||||
*/
|
||||
void xmpp_conn_set_keepalive(xmpp_conn_t *conn, int timeout, int interval)
|
||||
{
|
||||
conn->ka_timeout = timeout;
|
||||
conn->ka_interval = interval;
|
||||
conn->ka_count = 0;
|
||||
xmpp_conn_set_sockopt_callback(conn, xmpp_sockopt_cb_keepalive);
|
||||
}
|
||||
|
||||
68
src/sock.c
68
src/sock.c
@@ -33,8 +33,7 @@
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "sock.h"
|
||||
#include "snprintf.h"
|
||||
#include "common.h"
|
||||
|
||||
void sock_initialize(void)
|
||||
{
|
||||
@@ -69,7 +68,7 @@ static int _in_progress(int error)
|
||||
#endif
|
||||
}
|
||||
|
||||
sock_t sock_connect(const char *host, unsigned short port)
|
||||
sock_t sock_connect(xmpp_conn_t *conn, const char *host, unsigned short port)
|
||||
{
|
||||
sock_t sock;
|
||||
char service[6];
|
||||
@@ -95,6 +94,14 @@ sock_t sock_connect(const char *host, unsigned short port)
|
||||
if (sock < 0)
|
||||
continue;
|
||||
|
||||
if (conn->sockopt_cb != NULL)
|
||||
err = (conn->sockopt_cb)(conn, &sock);
|
||||
|
||||
if (err != 0) {
|
||||
sock_close(sock);
|
||||
continue;
|
||||
}
|
||||
|
||||
err = sock_set_nonblocking(sock);
|
||||
if (err == 0) {
|
||||
err = connect(sock, ainfo->ai_addr, ainfo->ai_addrlen);
|
||||
@@ -109,12 +116,17 @@ sock_t sock_connect(const char *host, unsigned short port)
|
||||
return sock;
|
||||
}
|
||||
|
||||
int sock_set_keepalive(sock_t sock, int timeout, int interval)
|
||||
int sock_set_keepalive(sock_t sock,
|
||||
int timeout,
|
||||
int interval,
|
||||
int count,
|
||||
unsigned int user_timeout)
|
||||
{
|
||||
int ret;
|
||||
int optval = (timeout && interval) ? 1 : 0;
|
||||
|
||||
/* This function doesn't change maximum number of keepalive probes */
|
||||
UNUSED(count);
|
||||
UNUSED(user_timeout);
|
||||
|
||||
#ifdef _WIN32
|
||||
struct tcp_keepalive ka;
|
||||
@@ -149,11 +161,57 @@ int sock_set_keepalive(sock_t sock, int timeout, int interval)
|
||||
return ret;
|
||||
#endif /* TCP_KEEPINTVL */
|
||||
}
|
||||
|
||||
if (count) {
|
||||
#ifdef TCP_KEEPCNT
|
||||
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &count, sizeof(count));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
#endif /* TCP_KEEPCNT */
|
||||
}
|
||||
|
||||
if (user_timeout) {
|
||||
#ifdef TCP_USER_TIMEOUT
|
||||
ret = setsockopt(sock, IPPROTO_TCP, TCP_USER_TIMEOUT, &user_timeout,
|
||||
sizeof(user_timeout));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
#elif defined(TCP_RXT_CONNDROPTIME)
|
||||
int rxt = user_timeout / 1000;
|
||||
ret = setsockopt(sock, IPPROTO_TCP, TCP_RXT_CONNDROPTIME, &rxt,
|
||||
sizeof(rxt));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
#endif /* TCP_USER_TIMEOUT */
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Example sockopt callback function
|
||||
* An example function that can be used to set reasonable default keepalive
|
||||
* options on sockets when registered for a connection with
|
||||
* xmpp_conn_set_sockopt_callback()
|
||||
*
|
||||
* @param conn a Strophe connection object
|
||||
* @param socket pointer to a socket descriptor
|
||||
*
|
||||
* @see xmpp_sockopt_callback for details on the `socket` parameter
|
||||
* @ingroup Connections
|
||||
*/
|
||||
int xmpp_sockopt_cb_keepalive(xmpp_conn_t *conn, void *socket)
|
||||
{
|
||||
sock_t sock = *((sock_t *)socket);
|
||||
|
||||
return sock_set_keepalive(
|
||||
sock, conn->ka_timeout, conn->ka_interval, conn->ka_count,
|
||||
conn->ka_count
|
||||
? (conn->ka_timeout + conn->ka_interval * conn->ka_count) * 1000
|
||||
: 0);
|
||||
}
|
||||
|
||||
int sock_close(sock_t sock)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
11
src/sock.h
11
src/sock.h
@@ -22,6 +22,9 @@
|
||||
typedef int sock_t;
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <iphlpapi.h>
|
||||
#include <mstcpip.h> /* tcp_keepalive */
|
||||
typedef SOCKET sock_t;
|
||||
#endif
|
||||
|
||||
@@ -30,7 +33,7 @@ void sock_shutdown(void);
|
||||
|
||||
int sock_error(void);
|
||||
|
||||
sock_t sock_connect(const char *host, unsigned short port);
|
||||
sock_t sock_connect(xmpp_conn_t *conn, const char *host, unsigned short port);
|
||||
int sock_close(sock_t sock);
|
||||
|
||||
int sock_set_blocking(sock_t sock);
|
||||
@@ -40,6 +43,10 @@ int sock_write(sock_t sock, const void *buff, size_t len);
|
||||
int sock_is_recoverable(int error);
|
||||
/* checks for an error after connect, return 0 if connect successful */
|
||||
int sock_connect_error(sock_t sock);
|
||||
int sock_set_keepalive(sock_t sock, int timeout, int interval);
|
||||
int sock_set_keepalive(sock_t sock,
|
||||
int timeout,
|
||||
int interval,
|
||||
int count,
|
||||
unsigned int user_timeout);
|
||||
|
||||
#endif /* __LIBSTROPHE_SOCK_H__ */
|
||||
|
||||
Reference in New Issue
Block a user