1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
/* Copyright 2010-2011 NORDUnet A/S. All rights reserved.
See LICENSE for licensing information. */
#if defined HAVE_CONFIG_H
#include <config.h>
#endif
#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 <radius/client.h>
#include "debug.h"
#include "conn.h"
#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
#define RAND 100 /* Rand factor, milliseconds. */
int
rs_request_create (struct rs_connection *conn, struct rs_request **req_out)
{
struct rs_request *req = rs_malloc (conn->ctx, sizeof(*req));
assert (req_out);
if (!req)
return rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL);
memset (req, 0, sizeof(*req));
req->conn = conn;
*req_out = req;
return RSE_OK;
}
void
rs_request_add_reqpkt (struct rs_request *req, struct rs_packet *req_msg)
{
assert (req);
req->req_msg = req_msg;
}
int
rs_request_create_authn (struct rs_connection *conn,
struct rs_request **req_out,
const char *user_name,
const char *user_pw)
{
struct rs_request *req = NULL;
assert (req_out);
if (rs_request_create (conn, &req))
return -1;
if (rs_packet_create_authn_request (conn, &req->req_msg, user_name, user_pw))
return -1;
if (req_out)
*req_out = req;
return RSE_OK;
}
void
rs_request_destroy (struct rs_request *request)
{
assert (request);
assert (request->conn);
assert (request->conn->ctx);
if (request->req_msg)
rs_packet_destroy (request->req_msg);
rs_free (request->conn->ctx, request);
}
static void
_rand_rt (struct timeval *res, uint32_t rtprev, uint32_t factor)
{
uint32_t ms = rtprev * (nr_rand () % factor);
res->tv_sec = rtprev + ms / 1000;
res->tv_usec = (ms % 1000) * 1000;
}
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};
const 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. */
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 (r != RSE_TIMEOUT_CONN && r != RSE_TIMEOUT_IO)
break; /* Error. */
/* Timing out reading or writing. Pop the timeout error from the
stack and continue the loop. */
rs_err_conn_pop (request->conn);
gettimeofday (&now, NULL);
if (++count > MRC || timercmp (&now, &end, >))
{
r = rs_err_conn_push_fl (request->conn, RSE_TIMEOUT,
__FILE__, __LINE__, NULL);
break; /* Timeout. */
}
/* rt = 2 * rt + rand_rt (rt, RAND); */
timeradd (&rt, &rt, &rt);
_rand_rt (&tmp_tv, IRT, RAND);
timeradd (&rt, &tmp_tv, &rt);
if (timercmp (&rt, &mrt_tv, >))
_rand_rt (&rt, MRT, RAND);
}
timerclear (&rt);
rs_conn_set_timeout (conn, &rt);
rs_debug (("%s: returning %d\n", __func__, r));
return r;
}
struct rs_packet *
rs_request_get_reqmsg (const struct rs_request *request)
{
assert (request);
return request->req_msg;
}
|