Все просто, как... ping
1. Не работает под пользователем с урезанными правами - выдается ошибка "Сделана попытка доступа к сокету методом запрещенным правами доступа".
2. При попытке пинговать не существующий узел - программа виснет, хотя согласно мелкомягкой документации должна выполняться после истечения некоторого заданного таймаута.Стандартный пинг в этих случаях пишет "Превышен интервал..." Например 150.65.65.65.
Я там уже все что мог пересмотрел, и вариантов 2 - либо в стандартном пинге опять-таки использованы какие-то недокументированные функции, либо я чего-то не досмотрел.
Сорцы пинга в прицепленном файле, если кому интересно и может помочь - буду благодарен.
В стандартном пинге эта проблема решается видимо так, как я сразу и подумал. Там 2 потока и наверняка один контролирует зависания второго. С этим понятно, сделаем. Теперь интересен первый вопрос.
Понятно что так делать - не хорошо. Потому нашел более корректный, и как выяснилось, более простой вариант. В виндах есть системная библиотека icmp.dll. Надо работать с ней. Пример ниже:
#include <Ipexport.h>
#include <stdio.h>
#include <conio.h>
//ДЕСКРИПТОР ДЛЯ ЗАГРУЗКИ СИСТЕМНОЙ БИБЛИОТЕКИ ICMP.DLL
HINSTANCE icmpdll;
//ОПРЕДЕЛЯЕМ ТИП УКАЗАТЕЛЯ НА ФУНКЦИЮ IcmpSendEcho:
typedef DWORD(CALLBACK* IcmpSendEcho)(HANDLE,IPAddr,LPVOID,WORD,
PIP_OPTION_INFORMATION,LPVOID,DWORD,DWORD);
//ОПРЕДЕЛЯЕМ ТИП УКАЗАТЕЛЯ НА ФУНКЦИЮ IcmpCreateFile
//HANDLE IcmpCreateFile(void);
typedef HANDLE (CALLBACK* IcmpCreateFile)(void);
//BOOL IcmpCloseHandle(HANDLE IcmpHandle);
typedef bool (CALLBACK* IcmpCloseHandle)(HANDLE IcmpHandle);
int main(void)
{
WSADATA wsaData;
if (WSAStartup(0x0101,&wsaData) != 0)
{
fprintf(stderr,"WSAStartup failed: %d\n",GetLastError());
return -1;
}
// Check WinSock version
if (0x0101 != wsaData.wVersion)
{
fprintf(stderr,"\nWinSock version 1.1 not supported\n");
WSACleanup();
return -1;
}
//ЗАГРУЖАЕМ БИБЛИОТЕКУ
icmpdll=LoadLibrary("icmp.dll");
if(!icmpdll)
{
printf("LoadLibrary failed!\n");
return -1;
}
//ОБЪЯВЛЯЕМ ССЫЛКИ НА ФУНКЦИИ ИЗ БИБЛИОТЕКИ ICMP.DLL
IcmpSendEcho icmp_echo;
IcmpCreateFile icmp_create_file;
IcmpCloseHandle close_icmp_file;
//ПРОИЗВОДИМ ИМПОРТ ФУНКЦИЙ
icmp_echo=(IcmpSendEcho)GetProcAddress(icmpdll,"IcmpSendEcho");
if(!(DWORD)icmp_echo)
{
printf("Faild get address IcmpSendEcho!\n");
return -1;
}
icmp_create_file=(IcmpCreateFile)GetProcAddress(icmpdll,"IcmpCreateFile");
if(!(DWORD)icmp_create_file)
{
printf("Faild get address IcmpCreateFile!\n");
return -1;
}
close_icmp_file=(IcmpCloseHandle)GetProcAddress(icmpdll,"IcmpCloseHandle");
if(!(DWORD)close_icmp_file)
{
printf("Faild get address IcmpCloseHandle!\n");
return -1;
}
//ПУСКАЕМ ПИНГ
char *SendData = "Data Buffer";
HANDLE hIcmpFile;
hIcmpFile=icmp_create_file();
if(hIcmpFile==INVALID_HANDLE_VALUE)
{
printf("Failed icmp_create_file!\n");
return -1;
}//else printf("Success icmp_create_file...\n");
//ICMP_ECHO_REPLY icmpEcho;
in_addr iaDest;
IP_OPTION_INFORMATION ipInfo;
ipInfo.Ttl= 128;
ipInfo.Tos = 0;
ipInfo.Flags= 0;
ipInfo.OptionsSize= 0;
ipInfo.OptionsData= NULL;
u_int packet_size=1024;
char *send_buffer=(char*)malloc(packet_size);
memset(send_buffer,'A',packet_size);
if(packet_size<8)packet_size=8;
LPVOID repl_buf=(VOID*) malloc(sizeof(ICMP_ECHO_REPLY) + packet_size);
for(int i=0;i<10;i++)
{
DWORD dwRet = icmp_echo(
hIcmpFile, // Handle from IcmpCreateFile()
inet_addr("10.65.5.1"), // Destination IP address
send_buffer, // Pointer to buffer to send
packet_size,// Size of buffer in bytes
&ipInfo, // Request options
repl_buf, // Reply buffer
packet_size+sizeof(ICMP_ECHO_REPLY),
3000); // Time to wait in milliseconds
// Print the results
// if(!dwRet)return -1;
PICMP_ECHO_REPLY icmpEcho = (PICMP_ECHO_REPLY)repl_buf;
iaDest.s_addr = icmpEcho->Address;
printf("Reply from %s Time=%ldms TTL=%d size=%u bytes; status: ",
inet_ntoa(iaDest),
icmpEcho->RoundTripTime,
icmpEcho->Options.Ttl,icmpEcho->DataSize);
switch(icmpEcho->Status)
{
case IP_SUCCESS: printf("IP_SUCCESS\n");break;
//ТУТ ЕЩЕ КУЧАЙ case'ов, ЗА ПОЯСНЕНИЯМИ СМ. ipexport.h
default: printf("Uncknown status!\n");break;
}
Sleep(500);
//getch();
}
free(repl_buf);
//ОСВОБОЖДАЕМ БИБЛИОТЕКУ
if(!FreeLibrary(icmpdll))
{
printf("FreeLibrary failed!\n");
return -1;
}
if(!CloseHandle(hIcmpFile))
{
printf("Failed close_icmp_file!\n");
return -1;
}
WSACleanup();
printf("Press any key to exit program...\n");
getch();
return 0;
}
Хорошо копаеш :).
Кстати, я был прав. Про недокументированные функции. Те функции что я заюзал применяются в traceroute. А в пинге используются отнюдь не они. Там ХЗ что юзается.
Кстати, я был прав. Про недокументированные функции. Те функции что я заюзал применяются в traceroute. А в пинге используются отнюдь не они. Там ХЗ что юзается.
Я вон отдизассемблил ping от в2к3 - там идут вызовы WSAIoctl, getaddrinfo, IcmpSendEcho2 и т.д. Документировано таки.
IcmpSendEcho2 и т.д. Документировано таки.
Согласен, щас не дома, потому сам глянуть не могу. Но! Во первых, IcmpSendEcho2!=IcmpSendEcho, а применять надо судя по ТЗ вроде как именно вторую. Но даже это ладно - если там только эти функции, то не хвататет как минимум IcmpCreateFile. Если смотреть msdn, то там вообще бред какой-то непонятный пишут :). Во первых в примере для IcmpSendEcho2 первые 3 параметра установлены в NULL. Ладно, допустим что это дефолтное значение. Только не очень понятно что и как там работает в общем. Проверять как она работает я даже не стал.
Смотрим функцию IcmpSendEcho - там дан откровенно не рабочий пример: неправильно указан размер буфера отправки. В примере он расчитывается из длинны данных и длинны icmp-ответа (sizeof(SendData) + sizeof(ICMP_ECHO_REPLY)) - при чем в запросе размер ответа, не очень понятно сразу, но фича в том, что оно вообще не работает, если не убрать sizeof(ICMP_ECHO_REPLY)!!! Возвращает ошибку о недостаточности размера приемного буфера который расчитывается так же. При чем нехватает как раз строго на длинну ICMP_ECHO_REPLY из чего можно сделать не сложный вывод :)
Ну и последнее. В самом конце доки на IcmpSendEcho написано: "Client Requires Windows Vista or Windows XP." И не меньше. Хотя в 2000-ной оно тоже есть и юзается самими же мелкософтами в tracert. И у меня в 2000-ной все на ура работает. Вывод: мелкософты сами заколбасились в своей документации по уши и не задокументировали толком ни первую, ни вторую функции.
ЗЫ Често говоря я не понимаю почему в tracert применяются одни функции, а в ping - другие. Хотя задачи выполняют одинаковые. Очередная замута MS.