Implement Ping network function.

This commit is contained in:
TomAwezome 2021-12-28 22:52:09 -05:00
parent 28ab32e893
commit 9857b67377
5 changed files with 102 additions and 4 deletions

View file

@ -18,6 +18,7 @@ Cd(__DIR__);;
#include "Utilities/BST"
#include "Protocols/UDP/MakeUDP"
#include "Protocols/DNS"
#include "Utilities/Ping"
#include "Protocols/TCP/MakeTCP"

View file

@ -13,6 +13,19 @@ class CICMPHeader
};
/* global variable containing last reply ICMP header received,
Ping() checks this to make ping report.
*/
CICMPHeader icmp_reply;
U0 ICMPInit()
{
MemSet(&icmp_reply, 0, sizeof(CICMPHeader));
}
NetQueueInit;
U16 ICMPChecksum(U8 *buf, I64 size)
{
U64 i, sum = 0;
@ -73,14 +86,12 @@ U0 ICMPReplySend(U32 destination_ip_address,
U0 ICMPRequestSend(U32 destination_ip_address,
U16 identifier,
U16 sequence_number,
U16 request_checksum,
U8 *payload,
I64 length)
{
U8 *icmp_frame;
I64 de_index;
CICMPHeader *header;
no_warn request_checksum; // TODO: needed? remove arg?
de_index = IPV4PacketAllocate(&icmp_frame,
IP_PROTOCOL_ICMP,
@ -131,6 +142,10 @@ I64 ICMPHandler(CIPV4Packet *packet)
packet->data + sizeof(CICMPHeader), // Data payload at IPV4Packet data location after the ICMP header
packet->length - sizeof(CICMPHeader));// Payload length is size of packet after dropping header.
}
else if (header->type == ICMP_TYPE_ECHO_REPLY && header->code == ICMP_CODE_ECHO)
{ // save the reply to the global ICMP reply header
MemCopy(&icmp_reply, header, sizeof(CICMPHeader));
}
else
NetWarn("ICMP HANDLER: Unhandled ICMP packet. type, code: 0x%X, 0x%X", header->type, header->code);
@ -138,3 +153,5 @@ I64 ICMPHandler(CIPV4Packet *packet)
return 0;
}
ICMPInit;

View file

@ -1,3 +1,4 @@
Cd(__DIR__);;
#include "Load"
NetConfigure;

View file

@ -7,7 +7,7 @@ U0 ICMPTest()
for (i = 0; i < 64; i++)
b[i] = RandU8;
ICMPRequestSend(a, 0, 0, 0, b, 64);
ICMPRequestSend(a, 0, 0, b, 64);
}
ICMPTest;

79
src/Home/Net/Utilities/Ping.ZC Executable file
View file

@ -0,0 +1,79 @@
I64 Ping(U8 *hostname, I64 timeout=JIFFY_FREQ)
{
U32 addr;
CAddressInfo *current;
CAddressInfo *result = NULL;
I64 error;
I64 i = 0, t, delay, sent = 0, min_delay = I64_MAX, max_delay = I64_MIN, sum_delay = 0;
CSocketAddressIPV4 *ipv4_address;
U16 sequence_number = 1, identifier = RandU16, count = 0;
U8 *payload;
if (!IPV4AddressParse(hostname, &addr))
{
error = DNSAddressInfoGet(hostname, NULL, &result);
if (error < 0)
{
NetErr("Ping: Failed at DNS Get Address Info.");
return -1;
}
current = result;
while (current)
{
if (current->family == AF_INET)
{
ipv4_address = current->address;
addr = EndianU32(ipv4_address->address); // why does it need EndianU32
break;
}
current = current->next;
}
}
if (!current)
{
NetErr("Ping: Failed to resolve address.");
return -1;
}
while (!CharScan)
{
payload = MAlloc(64);
for (i = 0; i < 64; i++)
payload[i] = RandU8;
"Sending Ping request #%d\n", sequence_number;
ICMPRequestSend(addr, identifier, EndianU16(sequence_number), payload, 64);
sent++;
t = counts.jiffies;
while (counts.jiffies < t + timeout)
{
if (icmp_reply.identifier == identifier && icmp_reply.sequence_number == EndianU16(sequence_number))
{
delay = counts.jiffies - t;
min_delay = MinI64(min_delay, delay);
max_delay = MaxI64(max_delay, delay);
sum_delay += delay; // sum up delays, divide through by count during stat report to get average
count++;
"\tReceived reply, delay: %dms\n", delay;
break;
}
Sleep(1);
}
while (counts.jiffies < t + JIFFY_FREQ)
Sleep(1);
sequence_number++;
Free(payload);
}
"\nPing Statistics:\n";
"\tSent: %d, Received: %d, Lost: %d (%0.02f %%)\n", sent, count, sent - count, 100.0 - 100.0 * count / sent;
if (min_delay != I64_MAX && max_delay != I64_MIN && sum_delay != 0)
"\tMin: %dms, Max: %dms, Avg: %dms\n", min_delay, max_delay, sum_delay / count;
"\n";
return count;
}