317 lines
8.9 KiB
C
317 lines
8.9 KiB
C
/******************************************************************************
|
|
libprozilla - a download accelerator library
|
|
Copyright (C) 2001 Kalum Somaratna
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
#include "common.h"
|
|
#include "prozilla.h"
|
|
#include "connect.h"
|
|
#include "misc.h"
|
|
#include "url.h"
|
|
#include "netrc.h"
|
|
#include "debug.h"
|
|
#include "ping.h"
|
|
|
|
|
|
|
|
#define TCP_PING_PACKSIZE 3
|
|
|
|
uerr_t tcp_ping(ping_t * ping_data)
|
|
{
|
|
int status, noblock, flags;
|
|
extern int h_errno;
|
|
struct timeval start_time;
|
|
struct timeval end_time;
|
|
char ping_buf[TCP_PING_PACKSIZE];
|
|
int bytes_read;
|
|
struct addrinfo hints, *res = NULL;
|
|
char szPort[10];
|
|
int error;
|
|
|
|
assert(ping_data->host);
|
|
memset(&hints, 0, sizeof(hints));
|
|
memset(szPort, 0, sizeof(szPort));
|
|
snprintf(szPort, sizeof(szPort), "%d", ping_data->port);
|
|
hints.ai_family = AF_INET;
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
error = getaddrinfo(ping_data->host, szPort, &hints, &res);
|
|
if (error)
|
|
{
|
|
return ping_data->err = HOSTERR;
|
|
}
|
|
|
|
if ((ping_data->sock = socket(res->ai_family, res->ai_socktype, IPPROTO_TCP)) < 1)
|
|
{
|
|
free(res);
|
|
return ping_data->err = CONSOCKERR;
|
|
}
|
|
|
|
/* Experimental. */
|
|
flags = fcntl(ping_data->sock, F_GETFL, 0);
|
|
if (flags != -1)
|
|
noblock = fcntl(ping_data->sock, F_SETFL, flags | O_NONBLOCK);
|
|
else
|
|
noblock = -1;
|
|
|
|
/* get start time */
|
|
gettimeofday(&start_time, 0);
|
|
|
|
status =
|
|
connect(ping_data->sock, res->ai_addr, res->ai_addrlen);
|
|
|
|
if ((status == -1) && (noblock != -1) && (errno == EINPROGRESS))
|
|
{
|
|
fd_set writefd;
|
|
|
|
FD_ZERO(&writefd);
|
|
FD_SET(ping_data->sock, &writefd);
|
|
|
|
status =
|
|
select((ping_data->sock + 1), NULL, &writefd, NULL,
|
|
&ping_data->timeout);
|
|
|
|
/* Do we need to retry if the err is EINTR? */
|
|
|
|
if (status > 0)
|
|
{
|
|
socklen_t arglen = sizeof(int);
|
|
|
|
if (getsockopt
|
|
(ping_data->sock, SOL_SOCKET, SO_ERROR, &status, &arglen) < 0)
|
|
status = errno;
|
|
|
|
if (status != 0)
|
|
errno = status, status = -1;
|
|
|
|
if (errno == EINPROGRESS)
|
|
errno = ETIMEDOUT;
|
|
}
|
|
else if (status == 0)
|
|
errno = ETIMEDOUT, status = -1;
|
|
}
|
|
|
|
if (status < 0)
|
|
{
|
|
close_sock(&ping_data->sock);
|
|
|
|
if (errno == ECONNREFUSED)
|
|
{
|
|
free(res);
|
|
return ping_data->err = CONREFUSED;
|
|
}
|
|
else if (errno == ETIMEDOUT)
|
|
{
|
|
free(res);
|
|
return ping_data->err = PINGTIMEOUT;
|
|
}
|
|
else
|
|
{
|
|
free(res);
|
|
return ping_data->err = CONERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
flags = fcntl(ping_data->sock, F_GETFL, 0);
|
|
|
|
if (flags != -1)
|
|
fcntl(ping_data->sock, F_SETFL, flags & ~O_NONBLOCK);
|
|
}
|
|
|
|
/* setsockopt(*sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt,
|
|
(int) sizeof(opt)); */
|
|
|
|
free(res);
|
|
|
|
|
|
/*So far so good connection established */
|
|
|
|
bytes_read =
|
|
krecv(ping_data->sock, ping_buf, TCP_PING_PACKSIZE, 0,
|
|
&ping_data->timeout);
|
|
close_sock(&ping_data->sock);
|
|
|
|
proz_debug("bytes read = %d", bytes_read);
|
|
if (bytes_read == -1)
|
|
{
|
|
if (errno == ETIMEDOUT)
|
|
return ping_data->err = PINGTIMEOUT;
|
|
else
|
|
return ping_data->err = READERR;
|
|
}
|
|
|
|
if (bytes_read == 0 || bytes_read < TCP_PING_PACKSIZE)
|
|
return ping_data->err = READERR;
|
|
|
|
/* the end time */
|
|
gettimeofday(&end_time, 0);
|
|
proz_timeval_subtract(&ping_data->ping_time, &end_time, &start_time);
|
|
|
|
|
|
/* standard_ping_milli_secs =(int)((((float)ping_data->ping_time.tv_usec/1000)+(((float)ping_data->ping_time.tv_sec)*1000))*3/(float)bytes_read);
|
|
|
|
ping_data->ping_time.tv_sec=standard_ping_milli_secs/1000;
|
|
ping_data->ping_time.tv_usec=standard_ping_milli_secs%1000;
|
|
*/
|
|
|
|
return ping_data->err = PINGOK;
|
|
}
|
|
|
|
|
|
void proz_mass_ping(ftps_request_t * request)
|
|
{
|
|
request->mass_ping_running = TRUE;
|
|
if (pthread_create(&request->mass_ping_thread, NULL,
|
|
(void *)&mass_ping, (void *)request) != 0)
|
|
proz_die(_("Error: Not enough system resources"));
|
|
}
|
|
|
|
void proz_cancel_mass_ping(ftps_request_t * request)
|
|
{
|
|
/*TODO Rewrite so that this will terminate the pingin threads as well */
|
|
request->mass_ping_running = FALSE;
|
|
pthread_cancel(request->mass_ping_thread);
|
|
pthread_join(request->mass_ping_thread, 0);
|
|
}
|
|
|
|
void mass_ping(ftps_request_t * request)
|
|
{
|
|
int i, j, k = 0, num_iter, num_left, simul_pings;
|
|
pthread_t *ping_threads;
|
|
ping_t *ping_requests;
|
|
|
|
|
|
simul_pings = request->max_simul_pings;
|
|
|
|
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
|
|
ping_threads = (pthread_t *)kmalloc(sizeof(pthread_t) * simul_pings);
|
|
ping_requests = kmalloc(sizeof(ping_t) * request->num_mirrors);
|
|
|
|
num_iter = request->num_mirrors / simul_pings;
|
|
num_left = request->num_mirrors % simul_pings;
|
|
proz_debug("Max simul pings=%d", simul_pings);
|
|
proz_debug("request->num_mirrors=%d", request->num_mirrors);
|
|
|
|
pthread_mutex_lock(&request->access_mutex);
|
|
request->mass_ping_running = TRUE;
|
|
pthread_mutex_unlock(&request->access_mutex);
|
|
|
|
|
|
k = 0;
|
|
|
|
for (i = 0; i < num_iter; i++)
|
|
{
|
|
for (j = 0; j < simul_pings; j++)
|
|
{
|
|
ping_t ping_request;
|
|
|
|
memset(ping_requests + k, 0, sizeof(ping_request));
|
|
/*FIXME */
|
|
ping_requests[k].timeout.tv_sec = request->ping_timeout.tv_sec;
|
|
ping_requests[k].timeout.tv_usec = request->ping_timeout.tv_usec;
|
|
ping_requests[k].host = strdup(request->mirrors[k].server_name);
|
|
ping_requests[k].port = 21;
|
|
|
|
if (pthread_create(&ping_threads[j], NULL,
|
|
(void *)&tcp_ping,
|
|
(void *)(ping_requests + k)) != 0)
|
|
proz_die("Error: Not enough system resources"
|
|
"to create thread!\n");
|
|
k++;
|
|
}
|
|
|
|
k -= simul_pings;
|
|
|
|
for (j = 0; j < simul_pings; j++)
|
|
{
|
|
/*Wait till the end of each thread. */
|
|
pthread_join(ping_threads[j], NULL);
|
|
if (ping_requests[k].err == PINGOK)
|
|
{
|
|
pthread_mutex_lock(&request->access_mutex);
|
|
request->mirrors[k].milli_secs =
|
|
(ping_requests[k].ping_time.tv_sec * 1000) +
|
|
(ping_requests[k].ping_time.tv_usec / 1000);
|
|
request->mirrors[k].status = RESPONSEOK;
|
|
pthread_mutex_unlock(&request->access_mutex);
|
|
}
|
|
else
|
|
{
|
|
pthread_mutex_lock(&request->access_mutex);
|
|
request->mirrors[k].status = NORESPONSE;
|
|
pthread_mutex_unlock(&request->access_mutex);
|
|
}
|
|
k++;
|
|
}
|
|
}
|
|
|
|
|
|
for (j = 0; j < num_left; j++)
|
|
{
|
|
ping_t ping_request;
|
|
|
|
memset(ping_requests + k, 0, sizeof(ping_request));
|
|
/*FIXME */
|
|
ping_requests[k].timeout.tv_sec = request->ping_timeout.tv_sec;
|
|
ping_requests[k].timeout.tv_usec = 0;
|
|
ping_requests[k].host = strdup(request->mirrors[k].server_name);
|
|
ping_requests[k].port = 21;
|
|
|
|
if (pthread_create(&ping_threads[j], NULL,
|
|
(void *)&tcp_ping,
|
|
(void *)(&ping_requests[k])) != 0)
|
|
proz_die("Error: Not enough system resources" "to create thread!\n");
|
|
|
|
k++;
|
|
}
|
|
|
|
k -= num_left;
|
|
|
|
for (j = 0; j < num_left; j++)
|
|
{
|
|
/*Wait till the end of each thread. */
|
|
pthread_join(ping_threads[j], NULL);
|
|
|
|
/*Wait till the end of each thread. */
|
|
pthread_join(ping_threads[j], NULL);
|
|
if (ping_requests[k].err == PINGOK)
|
|
{
|
|
pthread_mutex_lock(&request->access_mutex);
|
|
request->mirrors[k].milli_secs =
|
|
(ping_requests[k].ping_time.tv_sec * 1000) +
|
|
(ping_requests[k].ping_time.tv_usec / 1000);
|
|
request->mirrors[k].status = RESPONSEOK;
|
|
pthread_mutex_unlock(&request->access_mutex);
|
|
}
|
|
else
|
|
{
|
|
pthread_mutex_lock(&request->access_mutex);
|
|
request->mirrors[k].status = NORESPONSE;
|
|
pthread_mutex_unlock(&request->access_mutex);
|
|
}
|
|
k++;
|
|
}
|
|
|
|
proz_debug("mass_ping complete.");
|
|
pthread_mutex_lock(&request->access_mutex);
|
|
request->mass_ping_running = FALSE;
|
|
pthread_mutex_unlock(&request->access_mutex);
|
|
}
|