libradius: Use poll(2) to wait for RADIUS responses
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user