Skip to content

Commit

Permalink
refactor reconnect timer to avoid platform issues with time_t. Fix #28
Browse files Browse the repository at this point in the history
  • Loading branch information
Fabian Mauchle committed May 5, 2019
1 parent 1fcc7eb commit 524a096
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 111 deletions.
51 changes: 16 additions & 35 deletions dtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
static void setprotoopts(struct commonprotoopts *opts);
static char **getlistenerargs();
void *dtlslistener(void *arg);
int dtlsconnect(struct server *server, struct timeval *when, int timeout, char *text);
int dtlsconnect(struct server *server, int timeout, char *text);
void *dtlsclientrd(void *arg);
int clientradputdtls(struct server *server, unsigned char *rad);
void addserverextradtls(struct clsrvconf *conf);
Expand Down Expand Up @@ -514,9 +514,10 @@ void *dtlslistener(void *arg) {
return NULL;
}

int dtlsconnect(struct server *server, struct timeval *when, int timeout, char *text) {
struct timeval socktimeout, now, start = {0,0};
int dtlsconnect(struct server *server, int timeout, char *text) {
struct timeval socktimeout, now, start;
time_t wait;
int firsttry = 1;
X509 *cert;
SSL_CTX *ctx = NULL;
struct hostportres *hp;
Expand All @@ -532,12 +533,7 @@ int dtlsconnect(struct server *server, struct timeval *when, int timeout, char *
pthread_mutex_unlock(&server->lock);

hp = (struct hostportres *)list_first(server->conf->hostports)->data;

gettimeofday(&now, NULL);
if (when && (now.tv_sec - when->tv_sec) < 30 ) {
/* last connection was less than 30s ago. Delay next attempt */
start.tv_sec = now.tv_sec + 30 - (now.tv_sec - when->tv_sec);
}
gettimeofday(&start, NULL);

for (;;) {
/* ensure previous connection is properly closed */
Expand All @@ -549,30 +545,18 @@ int dtlsconnect(struct server *server, struct timeval *when, int timeout, char *
SSL_free(server->ssl);
server->ssl = NULL;

/* no sleep at startup or at first try */
if (start.tv_sec) {
gettimeofday(&now, NULL);
wait = abs(now.tv_sec - start.tv_sec);
wait = wait > 60 ? 60 : wait;
wait = connect_wait(start, server->connecttime, firsttry);
debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait);
sleep(wait);
firsttry = 0;

if (timeout && (now.tv_sec - start.tv_sec) > timeout) {
debug(DBG_DBG, "tlsconnect: timeout");
return 0;
}

if (wait < 1)
sleep(2);
else {
debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait);
sleep(wait);
}
debug(DBG_INFO, "tlsconnect: retry connecting to %s", server->conf->name);
} else {
gettimeofday(&start, NULL);
gettimeofday(&now, NULL);
if (timeout && (now.tv_sec - start.tv_sec) > timeout) {
debug(DBG_DBG, "tlsconnect: timeout");
return 0;
}
/* done sleeping */

debug(DBG_WARN, "dtlsconnect: trying to open DTLS connection to %s port %s", hp->host, hp->port);
debug(DBG_INFO, "dtlsconnect: connecting to %s port %s", hp->host, hp->port);

if ((server->sock = bindtoaddr(srcres, hp->addrinfo->ai_family, 0)) < 0)
continue;
Expand Down Expand Up @@ -617,7 +601,7 @@ int dtlsconnect(struct server *server, struct timeval *when, int timeout, char *

pthread_mutex_lock(&server->lock);
server->state = RSP_SERVER_STATE_CONNECTED;
gettimeofday(&server->lastconnecttry, NULL);
gettimeofday(&server->connecttime, NULL);
pthread_mutex_unlock(&server->lock);
pthread_mutex_lock(&server->newrq_mutex);
server->conreset = 1;
Expand Down Expand Up @@ -659,19 +643,16 @@ int clientradputdtls(struct server *server, unsigned char *rad) {
void *dtlsclientrd(void *arg) {
struct server *server = (struct server *)arg;
unsigned char *buf;
struct timeval lastconnecttry;

for (;;) {
/* yes, lastconnecttry is really necessary */
lastconnecttry = server->lastconnecttry;
buf = raddtlsget(server->ssl, 5, &server->lock);
if (!buf) {
if(SSL_get_shutdown(server->ssl) || server->lostrqs) {
if (SSL_get_shutdown(server->ssl))
debug (DBG_WARN, "tlscleintrd: connection to server %s lost", server->conf->name);
else if (server->lostrqs)
debug (DBG_WARN, "dtlsclientrd: server %s did not respond, closing connection.", server->conf->name);
dtlsconnect(server, &lastconnecttry, 0, "dtlsclientrd");
dtlsconnect(server, 0, "dtlsclientrd");
server->lostrqs = 0;
}
continue;
Expand Down
2 changes: 1 addition & 1 deletion radsecproxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -1823,7 +1823,7 @@ void *clientwr(void *arg) {
gettimeofday(&server->lastreply, NULL);

if (conf->pdef->connecter) {
if (!conf->pdef->connecter(server, NULL, server->dynamiclookuparg ? 5 : 0, "clientwr")) {
if (!conf->pdef->connecter(server, server->dynamiclookuparg ? 5 : 0, "clientwr")) {
server->state = RSP_SERVER_STATE_FAILING;
if (server->dynamiclookuparg) {
debug(DBG_WARN, "%s: connect failed, sleeping %ds",
Expand Down
4 changes: 2 additions & 2 deletions radsecproxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ struct server {
pthread_mutex_t lock;
pthread_t clientth;
uint8_t clientrdgone;
struct timeval lastconnecttry;
struct timeval connecttime;
struct timeval lastreply;
enum rsp_server_state state;
uint8_t lostrqs;
Expand Down Expand Up @@ -237,7 +237,7 @@ struct protodefs {
void (*setprotoopts)(struct commonprotoopts *);
char **(*getlistenerargs)();
void *(*listener)(void*);
int (*connecter)(struct server *, struct timeval *, int, char *);
int (*connecter)(struct server *, int, char *);
void *(*clientconnreader)(void*);
int (*clientradput)(struct server *, unsigned char *);
void (*addclient)(struct client *);
Expand Down
56 changes: 19 additions & 37 deletions tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
static void setprotoopts(struct commonprotoopts *opts);
static char **getlistenerargs();
void *tcplistener(void *arg);
int tcpconnect(struct server *server, struct timeval *when, int timeout, char * text);
int tcpconnect(struct server *server, int timeout, char * text);
void *tcpclientrd(void *arg);
int clientradputtcp(struct server *server, unsigned char *rad);
void tcpsetsrcres();
Expand Down Expand Up @@ -79,8 +79,9 @@ void tcpsetsrcres() {
AF_UNSPEC, NULL, protodefs.socktype);
}

int tcpconnect(struct server *server, struct timeval *when, int timeout, char *text) {
struct timeval now, start = {0,0};
int tcpconnect(struct server *server, int timeout, char *text) {
struct timeval now, start;
int firsttry = 1;
time_t wait;

debug(DBG_DBG, "tcpconnect: called from %s", text);
Expand All @@ -89,51 +90,35 @@ int tcpconnect(struct server *server, struct timeval *when, int timeout, char *t
if (server->state == RSP_SERVER_STATE_CONNECTED)
server->state = RSP_SERVER_STATE_RECONNECTING;

gettimeofday(&now, NULL);
if (when && (now.tv_sec - when->tv_sec) < 30 ) {
/* last connection was less than 30s ago. Delay next attempt */
start.tv_sec = now.tv_sec + 30 - (now.tv_sec - when->tv_sec);
}
gettimeofday(&start, NULL);

for (;;) {
if (server->sock >= 0)
close(server->sock);
server->sock = -1;

/* no sleep at startup or at first try */
if (start.tv_sec) {
gettimeofday(&now, NULL);
wait = abs(now.tv_sec - start.tv_sec);
wait = wait > 60 ? 60 : wait;

if (timeout && (now.tv_sec - start.tv_sec) > timeout) {
debug(DBG_DBG, "tlsconnect: timeout");
pthread_mutex_unlock(&server->lock);
return 0;
}

/* give up lock while sleeping for next try */
pthread_mutex_unlock(&server->lock);
if (wait < 1)
sleep(2);
else {
debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait);
sleep(wait);
}
pthread_mutex_lock(&server->lock);
debug(DBG_INFO, "tlsconnect: retry connecting to %s", server->conf->name);
} else {
gettimeofday(&start, NULL);
pthread_mutex_unlock(&server->lock);
wait = connect_wait(start, server->connecttime, firsttry);
debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait);
sleep(wait);
firsttry = 0;

gettimeofday(&now, NULL);
if (timeout && (now.tv_sec - start.tv_sec) > timeout) {
debug(DBG_DBG, "tcpconnect: timeout");
return 0;
}
pthread_mutex_lock(&server->lock);

debug(DBG_INFO, "tcpconnect: connecting to %s", server->conf->name);
if ((server->sock = connecttcphostlist(server->conf->hostports, srcres)) < 0)
continue;
if (server->conf->keepalive)
enable_keepalive(server->sock);
break;
}
server->state = RSP_SERVER_STATE_CONNECTED;
gettimeofday(&server->lastconnecttry, NULL);
gettimeofday(&server->connecttime, NULL);
server->lostrqs = 0;
pthread_mutex_unlock(&server->lock);
pthread_mutex_lock(&server->newrq_mutex);
Expand Down Expand Up @@ -230,16 +215,13 @@ int clientradputtcp(struct server *server, unsigned char *rad) {
void *tcpclientrd(void *arg) {
struct server *server = (struct server *)arg;
unsigned char *buf;
struct timeval lastconnecttry;

for (;;) {
/* yes, lastconnecttry is really necessary */
lastconnecttry = server->lastconnecttry;
buf = radtcpget(server->sock, server->dynamiclookuparg ? IDLE_TIMEOUT : 0);
if (!buf) {
if (server->dynamiclookuparg)
break;
tcpconnect(server, &lastconnecttry, 0, "tcpclientrd");
tcpconnect(server, 0, "tcpclientrd");
continue;
}

Expand Down
53 changes: 17 additions & 36 deletions tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
static void setprotoopts(struct commonprotoopts *opts);
static char **getlistenerargs();
void *tlslistener(void *arg);
int tlsconnect(struct server *server, struct timeval *when, int timeout, char *text);
int tlsconnect(struct server *server, int timeout, char *text);
void *tlsclientrd(void *arg);
int clientradputtls(struct server *server, unsigned char *rad);
void tlssetsrcres();
Expand Down Expand Up @@ -82,27 +82,21 @@ void tlssetsrcres() {
AF_UNSPEC, NULL, protodefs.socktype);
}

int tlsconnect(struct server *server, struct timeval *when, int timeout, char *text) {
struct timeval now, start = {0,0};
int tlsconnect(struct server *server, int timeout, char *text) {
struct timeval now, start;
time_t wait;
int firsttry = 1;
X509 *cert;
SSL_CTX *ctx = NULL;
unsigned long error;
int origflags;

debug(DBG_DBG, "tlsconnect: called from %s", text);
pthread_mutex_lock(&server->lock);

if (server->state == RSP_SERVER_STATE_CONNECTED)
server->state = RSP_SERVER_STATE_RECONNECTING;

pthread_mutex_unlock(&server->lock);

gettimeofday(&now, NULL);
if (when && (now.tv_sec - when->tv_sec) < 30 ) {
/* last connection was less than 30s ago. Delay next attempt */
start.tv_sec = now.tv_sec + 30 - (now.tv_sec - when->tv_sec);
}
gettimeofday(&start, NULL);

for (;;) {
/* ensure previous connection is properly closed */
Expand All @@ -114,29 +108,18 @@ int tlsconnect(struct server *server, struct timeval *when, int timeout, char *t
SSL_free(server->ssl);
server->ssl = NULL;

/* no sleep at startup or at first try */
if (start.tv_sec) {
gettimeofday(&now, NULL);
wait = abs(now.tv_sec - start.tv_sec);
wait = wait > 60 ? 60 : wait;

if (timeout && (now.tv_sec - start.tv_sec) > timeout) {
debug(DBG_DBG, "tlsconnect: timeout");
return 0;
}
wait = connect_wait(start, server->connecttime, firsttry);
debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait);
sleep(wait);
firsttry = 0;

if (wait < 1)
sleep(2);
else {
debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait);
sleep(wait);
}
debug(DBG_INFO, "tlsconnect: retry connecting to %s", server->conf->name);
} else {
gettimeofday(&start, NULL);
gettimeofday(&now, NULL);
if (timeout && (now.tv_sec - start.tv_sec) > timeout) {
debug(DBG_DBG, "tlsconnect: timeout");
return 0;
}
/* done sleeping */

debug(DBG_INFO, "tlsconnect: connecting to %s", server->conf->name);
if ((server->sock = connecttcphostlist(server->conf->hostports, srcres)) < 0)
continue;
if (server->conf->keepalive)
Expand Down Expand Up @@ -181,7 +164,7 @@ int tlsconnect(struct server *server, struct timeval *when, int timeout, char *t

pthread_mutex_lock(&server->lock);
server->state = RSP_SERVER_STATE_CONNECTED;
gettimeofday(&server->lastconnecttry, NULL);
gettimeofday(&server->connecttime, NULL);
server->lostrqs = 0;
pthread_mutex_unlock(&server->lock);
pthread_mutex_lock(&server->newrq_mutex);
Expand Down Expand Up @@ -357,11 +340,9 @@ int clientradputtls(struct server *server, unsigned char *rad) {
void *tlsclientrd(void *arg) {
struct server *server = (struct server *)arg;
unsigned char *buf;
struct timeval now, lastconnecttry;
struct timeval now;

for (;;) {
/* yes, lastconnecttry is really necessary */
lastconnecttry = server->lastconnecttry;
buf = radtlsget(server->ssl, 10, &server->lock);
if (!buf) {
if (SSL_get_shutdown(server->ssl) || server->lostrqs) {
Expand All @@ -371,7 +352,7 @@ void *tlsclientrd(void *arg) {
debug (DBG_WARN, "tlsclientrd: server %s did not respond, closing connection.", server->conf->name);
if (server->dynamiclookuparg)
break;
tlsconnect(server, &lastconnecttry, 0, "tlsclientrd");
tlsconnect(server, 0, "tlsclientrd");
}
if (server->dynamiclookuparg) {
gettimeofday(&now, NULL);
Expand Down
27 changes: 27 additions & 0 deletions util.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <poll.h>
#include <stdarg.h>
#include <assert.h>
#include <sys/time.h>
#include "debug.h"
#include "util.h"

Expand Down Expand Up @@ -251,6 +252,32 @@ int connecttcp(struct addrinfo *addrinfo, struct addrinfo *src, uint16_t timeout
return s;
}

time_t connect_wait(struct timeval attempt_start, struct timeval last_success, int firsttry) {
struct timeval now;

gettimeofday(&now, NULL);

if (attempt_start.tv_sec < last_success.tv_sec ||
attempt_start.tv_sec > now.tv_sec) {
debug(DBG_WARN, "connect_wait: invalid timers detected!");
return 60;
}

if (now.tv_sec - last_success.tv_sec < 30)
return 30 - (attempt_start.tv_sec - last_success.tv_sec);

if (firsttry)
return 0;

if (now.tv_sec - attempt_start.tv_sec < 2)
return 2;

if (now.tv_sec - attempt_start.tv_sec > 60)
return 60;

return now.tv_sec - attempt_start.tv_sec;
}

/* Local Variables: */
/* c-file-style: "stroustrup" */
/* End: */
1 change: 1 addition & 0 deletions util.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ void disable_DF_bit(int socket, struct addrinfo *res);
void enable_keepalive(int socket);
int bindtoaddr(struct addrinfo *addrinfo, int family, int reuse);
int connecttcp(struct addrinfo *addrinfo, struct addrinfo *src, uint16_t timeout);
time_t connect_wait(struct timeval attempt_start, struct timeval last_success, int firsttry);


/* Local Variables: */
Expand Down

0 comments on commit 524a096

Please sign in to comment.