diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/conn.c | 8 | ||||
| -rw-r--r-- | lib/err.c | 1 | ||||
| -rw-r--r-- | lib/include/radsec/radsec-impl.h | 1 | ||||
| -rw-r--r-- | lib/include/radsec/radsec.h | 9 | ||||
| -rw-r--r-- | lib/request.c | 72 | ||||
| -rw-r--r-- | lib/send.c | 6 | ||||
| -rw-r--r-- | lib/tcp.c | 9 | 
7 files changed, 80 insertions, 26 deletions
| @@ -64,6 +64,7 @@ rs_conn_create (struct rs_context *ctx, struct rs_connection **conn,  	  c->peers = r->peers;	/* FIXME: Copy instead?  */  	  for (p = c->peers; p; p = p->next)  	    p->conn = c; +	  c->timeout.tv_sec = r->timeout;  	  c->tryagain = r->retries;  	}        else @@ -313,3 +314,10 @@ rs_conn_receive_packet (struct rs_connection *conn,    return RSE_OK;  } +void +rs_conn_set_timeout(struct rs_connection *conn, struct timeval *tv) +{ +  assert (conn); +  assert (tv); +  conn->timeout = *tv; +} @@ -31,6 +31,7 @@ static const char *_errtxt[] = {    "connect timeout",		/* 16 RSE_TIMEOUT_CONN */    "invalid argument",		/* 17 RSE_INVAL */    "I/O timeout",		/* 18 RSE_TIMEOUT_IO */ +  "timeout",			/* 19 RSE_TIMEOUT */  };  #define ERRTXT_SIZE (sizeof(_errtxt) / sizeof(*_errtxt)) diff --git a/lib/include/radsec/radsec-impl.h b/lib/include/radsec/radsec-impl.h index a924fc9..49f9a35 100644 --- a/lib/include/radsec/radsec-impl.h +++ b/lib/include/radsec/radsec-impl.h @@ -75,6 +75,7 @@ struct rs_connection {      struct rs_peer *peers;      struct rs_peer *active_peer;      struct rs_error *err; +    struct timeval timeout;      char is_connecting;		/* FIXME: replace with a single state member */      char is_connected;		/* FIXME: replace with a single state member */      int fd;			/* Socket.  */ diff --git a/lib/include/radsec/radsec.h b/lib/include/radsec/radsec.h index fcd391d..5f8f4db 100644 --- a/lib/include/radsec/radsec.h +++ b/lib/include/radsec/radsec.h @@ -3,6 +3,7 @@  /* See the file COPYING for licensing information.  */  #include <unistd.h> +#include <sys/time.h>  enum rs_err_code {      RSE_OK = 0, @@ -21,9 +22,10 @@ enum rs_err_code {      RSE_INTERNAL = 13,      RSE_SSLERR = 14,		/* OpenSSL error.  */      RSE_INVALID_PKT = 15, -    RSE_TIMEOUT_CONN = 16, -    RSE_INVAL = 17, -    RSE_TIMEOUT_IO = 18, +    RSE_TIMEOUT_CONN = 16,	/* Connection timeout.  */ +    RSE_INVAL = 17,		/* Invalid argument.  */ +    RSE_TIMEOUT_IO = 18,	/* I/O timeout.  */ +    RSE_TIMEOUT = 19,		/* High level timeout.  */  };  enum rs_conn_type { @@ -111,6 +113,7 @@ int rs_conn_receive_packet(struct rs_connection *conn,  			   struct rs_packet *request,  			   struct rs_packet **pkt_out);  int rs_conn_fd(struct rs_connection *conn); +void rs_conn_set_timeout(struct rs_connection *conn, struct timeval *tv);  /* Peer -- client and server.  */  int rs_peer_create(struct rs_connection *conn, struct rs_peer **peer_out); diff --git a/lib/request.c b/lib/request.c index 8cb8b7e..b0a8eef 100644 --- a/lib/request.c +++ b/lib/request.c @@ -5,14 +5,26 @@  #include <config.h>  #endif -#include <time.h> +#include <stdint.h> +#include <stdlib.h>  #include <assert.h> +#include <sys/time.h>  #include <event2/event.h>  #include <radsec/radsec.h>  #include <radsec/radsec-impl.h>  #include <radsec/request.h>  #include <radsec/request-impl.h> +#include <freeradius/libradius.h> +#include "debug.h"  #include "conn.h" +#include "tcp.h" + +/* RFC 5080 2.2.1.  Retransmission Behavior.  */ +#define IRT 2 +#define MRC 5 +#define MRT 16 +#define MRD 30 +#define RAND 100		/* Rand factor, milliseconds. */  int  rs_request_create (struct rs_connection *conn, struct rs_request **req_out) @@ -61,29 +73,69 @@ rs_request_destroy (struct rs_request *request)    rs_free (request->conn->ctx, request);  } -#if 0  static void -_timer_cb (evutil_socket_t fd, short what, void *arg) - +_rand_rt (struct timeval *res, uint32_t rtprev, uint32_t factor)  { +  uint32_t ms = rtprev * (fr_rand () % factor); +  res->tv_sec = rtprev + ms / 1000; +  res->tv_usec = (ms % 1000) * 1000;  } -#endif  int  rs_request_send (struct rs_request *request, struct rs_packet **resp_msg)  { +  int r = 0;    struct rs_connection *conn = NULL; +  int count = 0; +  struct timeval rt = {0,0}; +  struct timeval end = {0,0}; +  struct timeval now = {0,0}; +  struct timeval tmp_tv = {0,0}; +  struct timeval mrt_tv = {MRT,0};    if (!request || !request->conn || !request->req_msg || !resp_msg)      return rs_err_conn_push_fl (conn, RSE_INVAL, __FILE__, __LINE__, NULL);    conn = request->conn;    assert (!conn_user_dispatch_p (conn)); /* This function is high level.  */ -  if (rs_packet_send (request->req_msg, request)) -    return -1; +  gettimeofday (&end, NULL); +  end.tv_sec += MRD; +  _rand_rt (&rt, IRT, RAND); +  while (1) +    { +      rs_conn_set_timeout (conn, &rt); +      r = rs_packet_send (request->req_msg, NULL); +      if (r == RSE_OK) +	{ +	  r = rs_conn_receive_packet (request->conn, +				      request->req_msg, +				      resp_msg); +	  if (r == RSE_OK) +	    break;		/* Success.  */ -  if (rs_conn_receive_packet (request->conn, request->req_msg, resp_msg)) -    return -1; +	  /* Timing out on receiving data or reconnecting a broken TCP +	     connection is ok.  */ +	  if (r != RSE_TIMEOUT_CONN && r != RSE_TIMEOUT_IO) +	    break;		/* Error.  */ +	} +      else if (r != RSE_TIMEOUT_CONN) /* Timeout on TCP connect is ok.  */ +	break;			      /* Error.  */ -  return RSE_OK; +      gettimeofday (&now, NULL); +      if (++count > MRC || timercmp (&now, &end, >)) +	{ +	  r = RSE_TIMEOUT; +	  break;		/* Timeout.  */ +	} + +      /* rt = 2 * rt + _rand_rt (rt, RAND); */ +      timeradd (&rt, &rt, &rt);	/* rt = 2 * rt */ +      _rand_rt (&tmp_tv, IRT, RAND); +      timeradd (&rt, &tmp_tv, &rt); +      if (timercmp (&rt, &mrt_tv, >)) +	_rand_rt (&rt, MRT, RAND); +    } + +  rs_debug (("%s: returning %d\n", __func__, r)); +  return r;  } @@ -18,12 +18,6 @@  #include "tcp.h"  #include "udp.h" -/* RFC 5080 2.2.1.  Retransmission Behavior */ -#define IRT 2 -#define MRC 5 -#define MRT 16 -#define MRD 30 -  static int  _conn_open (struct rs_connection *conn, struct rs_packet *pkt)  { @@ -37,7 +37,7 @@ _conn_timeout_cb (int fd, short event, void *data)        rs_debug (("%s: connection timeout on %p (fd %d) connecting to %p\n",  		 __func__, conn, conn->fd, conn->active_peer));        conn->is_connecting = 0; -      rs_err_conn_push_fl (conn, RSE_TIMEOUT_IO, __FILE__, __LINE__, NULL); +      rs_err_conn_push_fl (conn, RSE_TIMEOUT_CONN, __FILE__, __LINE__, NULL);        event_loopbreak (conn);      }  } @@ -256,16 +256,11 @@ tcp_write_cb (struct bufferevent *bev, void *ctx)  int  tcp_set_connect_timeout (struct rs_connection *conn)  { -  struct timeval tv; -    if (!conn->tev)      conn->tev = evtimer_new (conn->evb, _conn_timeout_cb, conn);    if (!conn->tev)      return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,  				"evtimer_new"); -  tv.tv_sec = conn->realm->timeout; -  tv.tv_usec = 0; -  evtimer_add (conn->tev, &tv); - +  evtimer_add (conn->tev, &conn->timeout);    return RSE_OK;  } | 
