BVT1801_ping
.pdf//
// ДЕКЛАРАЦИЯ БИБЛИОТЕК
//
#include <stdlib.h> |
// Содержит базовые методы |
|
#include <stdio.h> |
// Содержит метод для вывода информации в консоль |
|
#include <sys/socket.h> |
// Содержит методы для работы с сокетами |
|
#include <arpa/inet.h> |
// Содержит методы необходимые для запроса информации от DNS-серверов |
|
#include <netdb.h> |
// Содержит структуру и методы для работы с ip адресами |
|
#include <unistd.h> |
// Содержит метод usleep для задержки отправки пакетов |
|
#include <string.h> |
// Содержит метод bzero для обнуления пакета |
|
#include <netinet/ip_icmp.h> // Содержит методы необходимые для ICMP запроса |
||
#include <time.h> |
// Содержит методы для работы со временем |
|
#include <errno.h> |
// Коды ошибок |
|
// |
|
|
// |
ДЕКЛАРАЦИЯ ГЛОБАЛЬНЫХ ПЕРЕМЕННЫХ |
|
// |
|
|
int currentPackage; |
// Количество отправленных пакетов |
|
int countPackage; |
// Количество отправляемых пакетов |
|
char* ip; |
// IP адрес получателя |
|
char* domain; |
// Домен получателя |
|
char* pathLog; |
// Путь к файлу лога |
|
int errorCode; |
// Код ошибки |
|
struct ping_pkt pckt; |
// Пакет |
|
struct timespec time_start; // Время отправки пакета |
||
int sock; |
// Дескриптор сокета |
|
struct sockaddr_in sockAddr;// Настройки адреса сокета |
||
FILE* fp; |
// Log файл |
|
char logText[100]; |
// Текст для записи в log файл |
|
// |
|
|
// |
ДЕКЛАРАЦИЯ ПРОЦЕДУР |
|
// |
|
|
struct ping_pkt |
// Структура пакета |
|
{ |
|
|
struct icmphdr hdr;
char msg[64 - sizeof(struct icmphdr)];
}; |
|
|
unsigned short checksum(void* b, int len) |
// Контрольная сумма |
|
{ |
|
|
//ДЕКЛАРАЦИЯ ПЕРЕМЕННЫХ |
|
|
unsigned short* buf; |
//Буфер |
|
unsigned int sum; |
//Промежуточная сумма |
|
unsigned short result; |
//Результат |
|
//ИНИЦИАЛИЗАЦИЯ ПЕРЕМЕННЫХ |
|
|
buf = b; |
|
|
sum = 0; |
|
|
result = 0; |
|
|
//ТЕЛО ПРОЦЕДУРЫ |
|
|
//printf("Вошли в checksum\n"); |
//Debug |
|
for (sum = 0; len > 1; len -= 2) |
|
|
sum += *buf++; |
|
|
if (len == 1) |
|
|
sum += *(unsigned char*)buf; |
|
|
sum = (sum >> 16) + (sum & 0xFFFF); |
|
|
sum += (sum >> 16); |
|
|
result = ~sum; |
|
|
//printf("Вышли из checksum\n"); |
//Debug |
|
return result; |
|
|
} |
|
|
int InitLog() { |
|
|
//printf("Вошли в InitLog\n"); |
//Debug |
|
if ((fp = fopen(pathLog, "w")) == NULL) { |
|
|
//printf("Вышли из InitLog: 1\n"); |
//Debug |
|
return 1; |
|
|
} |
|
|
//printf("Вышли из InitLog: 0\n"); |
//Debug |
return 0;
} |
|
int Log() { |
// Запись информации в лог файл |
//printf("Вошли в Log\n"); |
//Debug |
if (fprintf(fp, "%s\n", logText)>=0) |
|
{ |
|
//printf("Вышли из Log: 0\n"); |
//Debug |
return 0; |
|
} |
|
else |
|
{ |
|
//printf("Вышли из Log: 1\n"); |
//Debug |
return 1; |
|
} |
|
} |
|
void DiagLog() |
// Диагностика ошибки лога |
{ |
|
printf("Вошли в DiagLog\n"); |
|
switch(errno){ |
|
case E2BIG:
printf("Error: Input conversion stopped due to lack of space in the output buffer\n"); break;
case EILSEQ:
printf("Error: Input conversion stopped due to an input byte that does not belong to the input codeset\n"); break;
case EINVAL:
printf("Error: Input conversion stopped due to an incomplete character or shift sequence at the end of the input buffer\n"); break;
case EPERM:
printf("Error: Operation not permitted\n"); break;
case ENOENT:
printf("Error: No such file or directory\n"); break;
case EACCES:
printf("Error: Permission denied\n"); break;
case EMFILE:
printf("Error: Too many open files\n"); break;
case ENOMEM:
printf("Error: Out of memory\n"); break;
case EOVERFLOW:
printf("Error: Value too large for defined data type\n"); break;
} |
|
printf("Вышли из DiagLog\n"); |
|
} |
|
void Diag() |
// Диагностика ошибки в параметрах, отправке и получение пакета |
{ |
|
printf("Вошли в Diag\n"); |
|
switch(errorCode){ |
|
case 1: |
|
sprintf(logText,"Error: Wrong number of input parameters"); break;
case 2:
sprintf(logText,"Error: Domain doesn't match to any IP address"); break;
case 3:
sprintf(logText,"Error: Wrong initialization socket"); break;
case 4:
sprintf(logText,"Error: Wrong sending packet"); break;
case 5:
sprintf(logText,"Error: The number of sent parts of the package does not match the number of received"); break;
case 6:
sprintf(logText,"Error: The amount of the received packet does not match the sent");
break;
}
printf("Вышли из Diag\n");
} |
|
|
int InitICMP(struct sockaddr_in* sockAddr) |
// Инициализация сокета и адреса |
|
{ |
|
|
//ДЕКЛАРАЦИЯ ПЕРЕМЕННЫХ |
|
|
struct timeval tv_out; |
//Настройки времени для сокета |
|
int ttl_val; |
//Размер пакета |
|
//ИНИЦИАЛИЗАЦИЯ ПЕРЕМЕННЫХ |
|
|
ttl_val = 64; |
|
|
//ТЕЛО ПРОЦЕДУРЫ |
|
|
//printf("Вошли в InitICMP\n"); |
//Debug |
|
sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); |
|
|
if (sock < 0) |
|
// Успешно ли создался? |
{ |
|
|
//printf("Вышли из InitICMP: 1\n"); |
//Debug |
|
errorCode = 3; |
|
|
return 1; |
|
|
} |
|
|
else |
|
|
{ |
|
|
(*sockAddr).sin_family = AF_INET; |
// Заполняем адрес |
(*sockAddr).sin_port = htons(0); (*sockAddr).sin_addr.s_addr = inet_addr(ip);
tv_out.tv_sec = 1; // Заполняем настройки для соединения tv_out.tv_usec = 0;
setsockopt(sock, SOL_IP, IP_TTL, &ttl_val, sizeof(ttl_val));
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv_out, sizeof tv_out);
//printf("Вышли из InitICMP: 0\n"); |
//Debug |
return 0; |
|
} |
|
} |
|
|
int MakeICMPRequest(struct sockaddr_in* sockAddr) |
// Отправляем пакет |
|
{ |
|
|
//ДЕКЛАРАЦИЯ ПЕРЕМЕННЫХ |
|
|
int msg_count; |
//Количество ожидаемых пакетов |
|
int i; |
//Счетчик пакетов |
|
//ИНИЦИАЛИЗАЦИЯ ПЕРЕМЕННЫХ |
|
|
msg_count = 0; |
|
|
i = 0; |
|
|
//ТЕЛО ПРОЦЕДУРЫ |
|
|
//printf("Вошли в MakeICMPRequest\n"); |
//Debug |
|
//printf("currentPackage: %d\n",currentPackage);//Debug |
||
if (currentPackage >= countPackage) |
// Все пакеты были отправлены? |
|
{ |
|
|
//printf("Вышли из MakeICMPRequest: 2\n"); |
//Debug |
|
return 2; |
|
|
} |
|
|
else |
|
|
{ |
|
|
bzero(&pckt, sizeof(pckt)); |
|
|
pckt.hdr.type = ICMP_ECHO; |
// Инициализируем пакет для отправки |
|
pckt.hdr.un.echo.id = getpid(); |
|
for (i = 0; i < sizeof(pckt.msg) - 1; i++) pckt.msg[i] = i + '0';
pckt.msg[i] = 0; pckt.hdr.un.echo.sequence = msg_count++;
pckt.hdr.checksum = checksum(&pckt, sizeof(pckt));
usleep(1000000); |
// Задержка отправки пакета |
clock_gettime(CLOCK_MONOTONIC, &time_start);
if (sendto(sock, &pckt, sizeof(pckt), 0, |
// Отправка пакета |
(struct sockaddr*)sockAddr, |
|
sizeof(*sockAddr)) <= 0) |
|
{ |
|
//printf("Вышли из MakeICMPRequest: 1\n");//Debug errorCode = 4;
return 1;
}
currentPackage++;
//printf("Вышли из MakeICMPRequest: 0\n"); //Debug return 0;
}
} |
|
int MakeICMPReplay() |
// Дожидаемся пакета в ответ |
{ |
|
//ДЕКЛАРАЦИЯ ПЕРЕМЕННЫХ |
|
long double rtt_msec; |
//Разница между отправкой и прибытием |
int msg_count; |
//Количество пакетов |
int addr_len; |
//Размер адреса |
struct timespec time_end; |
//Время прибытия |
struct sockaddr_in r_addr; |
//Адрес |
double timeElapsed; |
//Прошедшее время |
struct tm *uTime; |
//Структура для вывод времени |
//ИНИЦИАЛИЗАЦИЯ ПЕРЕМЕННЫХ |
|
rtt_msec = 0; |
|
msg_count = 0; |
|
addr_len = sizeof(r_addr); |
|
//ТЕЛО ПРОЦЕДУРЫ
//printf("Вошли в MakeICMPReplay:\n"); //Debug if (recvfrom(sock, &pckt, sizeof(pckt), 0,
(struct sockaddr*)&r_addr, &addr_len) <= 0 && msg_count > 1)
{
//printf("Вышли из MakeICMPReplay: 1\n"); |
//Debug |
errorCode = 5; |
|
return 1; |
|
} |
|
else |
|
{ |
|
clock_gettime(CLOCK_MONOTONIC, &time_end); |
// Запоминаем время отправки |
timeElapsed = ((double)(time_end.tv_nsec - time_start.tv_nsec)) / 1000000.0; rtt_msec = (time_end.tv_sec - time_start.tv_sec) * 1000.0 + timeElapsed;
if (!(pckt.hdr.type == 69 && pckt.hdr.code == 0)) // Пришел верный ответ?
{
//printf("Error..Packet received with ICMP type %d code %d\n", pckt.hdr.type, pckt.hdr.code); //printf("Вышли из MakeICMPReplay: 1\n"); //Debug
errorCode = 6; return 1;
}
else
{
char strTime[40] = { 0 };
const time_t timer = time(NULL); uTime = localtime(&timer);
strftime(strTime, 80, "%H:%M:%S", uTime);
sprintf(logText,"[%s] %s %s количество байт = 64, RTT = %Lf ms",strTime, ip, domain, rtt_msec); printf("%s %s количество байт = 64, RTT = %Lf ms\n", ip, domain, rtt_msec);
//printf("Вышли из MakeICMPReplay: 0\n"); |
//Debug |
return 0; |
|
} |
|
} |
|
} |
|
int GetIP() |
// Получаем IP адрес на основе домена |
{ |
|
//ДЕКЛАРАЦИЯ ПЕРЕМЕННЫХ |
|
struct hostent* ghbn; //Запрос к DNS серверу |
|
//ИНИЦИАЛИЗАЦИЯ ПЕРЕМЕННЫХ |
|
ghbn = gethostbyname(domain); |
// создаем структуру на основе домена |
//ТЕЛО ПРОЦЕДУРЫ
//printf("Вошли в GetIP\n"); //Debug //printf("DOMAIN: "); printf(domain); printf("\n"); //Debug
if (ghbn) |
// Если структура была созданна, значит соответствующему домену найден ip |
{ |
|
ip = inet_ntoa(*(struct in_addr*)ghbn->h_addr); //сохраняем полученный ip printf("IP: "); printf(ip); printf("\n");
//printf("Вышли из GetIP: 0\n"); //Debug return 0;
} |
|
|
else |
|
|
{ |
|
|
//printf("Вышли из GetIP: 1\n"); |
//Debug |
|
errorCode = 2; |
|
|
return 1; |
|
//Для данного домена не найден ip |
} |
|
|
} |
|
|
int ReadingParams(int argc, char* argv[]) |
// Проверяем указанные параметры на валидность и присваиваем значения глобаль |
|
ным переменным |
|
|
{ |
|
|
//ДЕКЛАРАЦИЯ ПЕРЕМЕННЫХ |
|
|
long int a; |
//Очередной байт ip адреса |
|
char* endptr; |
//char представление адреса |
|
//ИНИЦИАЛИЗАЦИЯ ПЕРЕМЕННЫХ |
|
|
char* IP = argv[1]; |
|
|
//ТЕЛО ПРОЦЕДУРЫ |
|
|
//printf("Вошли в ReadingParams\n"); |
//Debug |
if (argc != 4)
{
errorCode = 1; return 1;
}
countPackage = atoi(argv[2]); pathLog = argv[3];
if (a = strtol(IP, &endptr, 10)) if (a >= 0 && a <= 255)
{
int i;
for (i = 0; i < 3; i++)
{
++endptr;
if (!(a = strtol(endptr, &endptr, 10)) || !(a >= 0 && a <= 255))
{
domain = IP; |
|
//printf("Вышли из ReadingParams: 2\n"); |
//Debug |
return 2; |
|
} |
|
} |
|
if (i < 3) |
|
{ |
|
domain = IP; |
|
//printf("Вышли из ReadingParams: 2\n"); |
//Debug |
return 2; |
|
} |
|
else |
|
{ |
|
ip = IP; |
|
//printf("Вышли из ReadingParams: 0\n"); |
//Debug |
return 0; |
|
} |
|
} |
|
else |
|
{ |
|