libradius: Use poll(2) to wait for RADIUS responses

This commit is contained in:
Martin Willi
2014-11-21 11:16:48 +01:00
parent fc829ec9fb
commit 1abaff6a3c
+41 -46
View File
@@ -129,7 +129,7 @@ METHOD(radius_socket_t, request, radius_message_t*,
private_radius_socket_t *this, radius_message_t *request)
{
chunk_t data;
int i, *fd;
int i, *fd, retransmit = 0;
u_int16_t port;
rng_t *rng = NULL;
@@ -166,64 +166,59 @@ METHOD(radius_socket_t, request, radius_message_t*,
for (i = 2; i <= 5; i++)
{
radius_message_t *response;
bool retransmit = FALSE;
struct timeval tv;
char buf[4096];
fd_set fds;
int res;
struct pollfd pfd = {
.fd = *fd,
.events = POLLIN,
};
if (retransmit)
{
DBG1(DBG_CFG, "retransmitting RADIUS %N (attempt %d)",
radius_message_code_names, request->get_code(request),
retransmit);
}
if (send(*fd, data.ptr, data.len, 0) != data.len)
{
DBG1(DBG_CFG, "sending RADIUS message failed: %s", strerror(errno));
return NULL;
}
tv.tv_sec = i;
tv.tv_usec = 0;
while (TRUE)
res = poll(&pfd, 1, i * 1000);
if (res < 0)
{
FD_ZERO(&fds);
FD_SET(*fd, &fds);
res = select((*fd) + 1, &fds, NULL, NULL, &tv);
/* TODO: updated tv to time not waited. Linux does this for us. */
if (res < 0)
{ /* failed */
DBG1(DBG_CFG, "waiting for RADIUS message failed: %s",
strerror(errno));
break;
}
if (res == 0)
{ /* timeout */
DBG1(DBG_CFG, "retransmitting RADIUS message");
retransmit = TRUE;
break;
}
res = recv(*fd, buf, sizeof(buf), MSG_DONTWAIT);
if (res <= 0)
{
DBG1(DBG_CFG, "receiving RADIUS message failed: %s",
strerror(errno));
break;
}
response = radius_message_parse(chunk_create(buf, res));
if (response)
{
if (response->verify(response,
request->get_authenticator(request), this->secret,
this->hasher, this->signer))
{
return response;
}
response->destroy(response);
}
DBG1(DBG_CFG, "received invalid RADIUS message, ignored");
DBG1(DBG_CFG, "waiting for RADIUS message failed: %s",
strerror(errno));
return NULL;
}
if (!retransmit)
if (res == 0)
{ /* timeout */
retransmit++;
continue;
}
res = recv(*fd, buf, sizeof(buf), MSG_DONTWAIT);
if (res <= 0)
{
break;
DBG1(DBG_CFG, "receiving RADIUS message failed: %s",
strerror(errno));
return NULL;
}
response = radius_message_parse(chunk_create(buf, res));
if (response)
{
if (response->verify(response,
request->get_authenticator(request), this->secret,
this->hasher, this->signer))
{
return response;
}
response->destroy(response);
}
DBG1(DBG_CFG, "received invalid RADIUS message, ignored");
return NULL;
}
DBG1(DBG_CFG, "RADIUS server is not responding");
DBG1(DBG_CFG, "RADIUS %N timed out after %d retransmits",
radius_message_code_names, request->get_code(request), retransmit - 1);
return NULL;
}