mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-05-21 18:42:53 +00:00
More work on IPv4 sockets and /bin/ping.
It's now actually possible to ping other hosts on the network! :^) I've switched the "run" script over to starting QEMU with user networking since that works better for my testing needs right now.
This commit is contained in:
parent
ce7c302933
commit
cf250e1245
Notes:
sideshowbarker
2024-07-19 15:04:33 +09:00
Author: https://github.com/awesomekling
Commit: cf250e1245
7 changed files with 125 additions and 38 deletions
|
@ -143,15 +143,16 @@ ssize_t IPv4Socket::recvfrom(void* buffer, size_t buffer_length, int flags, cons
|
||||||
}
|
}
|
||||||
|
|
||||||
auto peer_address = IPv4Address((const byte*)&((const sockaddr_in*)addr)->sin_addr.s_addr);
|
auto peer_address = IPv4Address((const byte*)&((const sockaddr_in*)addr)->sin_addr.s_addr);
|
||||||
|
#ifdef IPV4_SOCKET_DEBUG
|
||||||
kprintf("recvfrom: peer_address=%s\n", peer_address.to_string().characters());
|
kprintf("recvfrom: peer_address=%s\n", peer_address.to_string().characters());
|
||||||
|
#endif
|
||||||
|
|
||||||
ByteBuffer packet_buffer;
|
ByteBuffer packet_buffer;
|
||||||
|
|
||||||
{
|
{
|
||||||
LOCKER(m_lock);
|
LOCKER(m_lock);
|
||||||
if (!m_receive_queue.is_empty()) {
|
if (!m_receive_queue.is_empty()) {
|
||||||
packet_buffer = m_receive_queue.take_first();
|
packet_buffer = m_receive_queue.take_first();
|
||||||
m_can_read = m_receive_queue.is_empty();
|
m_can_read = !m_receive_queue.is_empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (packet_buffer.is_null()) {
|
if (packet_buffer.is_null()) {
|
||||||
|
@ -163,7 +164,7 @@ ssize_t IPv4Socket::recvfrom(void* buffer, size_t buffer_length, int flags, cons
|
||||||
ASSERT(m_can_read);
|
ASSERT(m_can_read);
|
||||||
ASSERT(!m_receive_queue.is_empty());
|
ASSERT(!m_receive_queue.is_empty());
|
||||||
packet_buffer = m_receive_queue.take_first();
|
packet_buffer = m_receive_queue.take_first();
|
||||||
m_can_read = m_receive_queue.is_empty();
|
m_can_read = !m_receive_queue.is_empty();
|
||||||
}
|
}
|
||||||
ASSERT(!packet_buffer.is_null());
|
ASSERT(!packet_buffer.is_null());
|
||||||
auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.pointer());
|
auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.pointer());
|
||||||
|
@ -174,8 +175,10 @@ ssize_t IPv4Socket::recvfrom(void* buffer, size_t buffer_length, int flags, cons
|
||||||
|
|
||||||
void IPv4Socket::did_receive(ByteBuffer&& packet)
|
void IPv4Socket::did_receive(ByteBuffer&& packet)
|
||||||
{
|
{
|
||||||
|
#ifdef IPV4_SOCKET_DEBUG
|
||||||
|
kprintf("IPv4Socket(%p): did_receive %d bytes\n", this, packet.size());
|
||||||
|
#endif
|
||||||
LOCKER(m_lock);
|
LOCKER(m_lock);
|
||||||
kprintf("IPv4Socket(%p): did_receive %d bytes\n", packet.size());
|
|
||||||
m_receive_queue.append(move(packet));
|
m_receive_queue.append(move(packet));
|
||||||
m_can_read = true;
|
m_can_read = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,11 @@ if [ "$1" = "b" ]; then
|
||||||
elif [ "$1" = "qn" ]; then
|
elif [ "$1" = "qn" ]; then
|
||||||
# ./run qn: qemu without network
|
# ./run qn: qemu without network
|
||||||
qemu-system-i386 -s -m 32 -device e1000 -drive format=raw,file=.floppy-image,if=floppy -drive format=raw,file=_fs_contents #$@
|
qemu-system-i386 -s -m 32 -device e1000 -drive format=raw,file=.floppy-image,if=floppy -drive format=raw,file=_fs_contents #$@
|
||||||
else
|
elif [ "$1" = "qtap" ]; then
|
||||||
echo run with net
|
# ./run qtap: qemu with tap
|
||||||
# ./run: qemu with network
|
|
||||||
sudo qemu-system-i386 -s -m 32 -object filter-dump,id=hue,netdev=br0,file=e1000.pcap -netdev tap,ifname=tap0,id=br0 -device e1000,netdev=br0 -drive format=raw,file=.floppy-image,if=floppy -drive format=raw,file=_fs_contents
|
sudo qemu-system-i386 -s -m 32 -object filter-dump,id=hue,netdev=br0,file=e1000.pcap -netdev tap,ifname=tap0,id=br0 -device e1000,netdev=br0 -drive format=raw,file=.floppy-image,if=floppy -drive format=raw,file=_fs_contents
|
||||||
|
else
|
||||||
|
# ./run: qemu with user networking
|
||||||
|
qemu-system-i386 -s -m 32 -object filter-dump,id=hue,netdev=breh,file=e1000.pcap -netdev user,id=breh -device e1000,netdev=breh -drive format=raw,file=.floppy-image,if=floppy -drive format=raw,file=_fs_contents
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ typedef dword gid_t;
|
||||||
typedef signed_word pid_t;
|
typedef signed_word pid_t;
|
||||||
typedef dword time_t;
|
typedef dword time_t;
|
||||||
typedef dword useconds_t;
|
typedef dword useconds_t;
|
||||||
typedef dword suseconds_t;
|
typedef signed_dword suseconds_t;
|
||||||
|
|
||||||
struct timeval {
|
struct timeval {
|
||||||
time_t tv_sec;
|
time_t tv_sec;
|
||||||
|
|
|
@ -11,9 +11,41 @@ const char* inet_ntop(int af, const void* src, char* dst, socklen_t len)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto* bytes = (const unsigned char*)src;
|
auto* bytes = (const unsigned char*)src;
|
||||||
snprintf(dst, len, "%u.%u.%u.%u", bytes[3], bytes[2], bytes[1], bytes[0]);
|
snprintf(dst, len, "%u.%u.%u.%u", bytes[0], bytes[1], bytes[2], bytes[3]);
|
||||||
return (const char*)dst;
|
return (const char*)dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int inet_pton(int af, const char* src, void* dst)
|
||||||
|
{
|
||||||
|
if (af != AF_INET) {
|
||||||
|
errno = EAFNOSUPPORT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
unsigned a;
|
||||||
|
unsigned b;
|
||||||
|
unsigned c;
|
||||||
|
unsigned d;
|
||||||
|
int count = sscanf(src, "%u.%u.%u.%u", &a, &b, &c, &d);
|
||||||
|
if (count != 4) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
uint8_t a;
|
||||||
|
uint8_t b;
|
||||||
|
uint8_t c;
|
||||||
|
uint8_t d;
|
||||||
|
};
|
||||||
|
uint32_t l;
|
||||||
|
} u;
|
||||||
|
u.a = a;
|
||||||
|
u.b = b;
|
||||||
|
u.c = c;
|
||||||
|
u.d = d;
|
||||||
|
*(uint32_t*)dst = u.l;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
const char* inet_ntop(int af, const void* src, char* dst, socklen_t);
|
const char* inet_ntop(int af, const void* src, char* dst, socklen_t);
|
||||||
|
int inet_pton(int af, const char* src, void* dst);
|
||||||
|
|
||||||
static inline uint16_t htons(uint16_t hs)
|
static inline uint16_t htons(uint16_t hs)
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,7 +30,7 @@ typedef uint32_t blksize_t;
|
||||||
typedef uint32_t blkcnt_t;
|
typedef uint32_t blkcnt_t;
|
||||||
typedef uint32_t time_t;
|
typedef uint32_t time_t;
|
||||||
typedef uint32_t useconds_t;
|
typedef uint32_t useconds_t;
|
||||||
typedef uint32_t suseconds_t;
|
typedef int32_t suseconds_t;
|
||||||
typedef uint32_t clock_t;
|
typedef uint32_t clock_t;
|
||||||
typedef uint32_t socklen_t;
|
typedef uint32_t socklen_t;
|
||||||
|
|
||||||
|
|
|
@ -4,23 +4,32 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <Kernel/NetworkOrdered.h>
|
#include <time.h>
|
||||||
|
|
||||||
NetworkOrdered<word> internet_checksum(const void* ptr, size_t count)
|
uint16_t internet_checksum(const void* ptr, size_t count)
|
||||||
{
|
{
|
||||||
dword checksum = 0;
|
uint32_t checksum = 0;
|
||||||
auto* w = (const word*)ptr;
|
auto* w = (const uint16_t*)ptr;
|
||||||
while (count > 1) {
|
while (count > 1) {
|
||||||
checksum += convert_between_host_and_network(*w++);
|
checksum += ntohs(*w++);
|
||||||
if (checksum & 0x80000000)
|
if (checksum & 0x80000000)
|
||||||
checksum = (checksum & 0xffff) | (checksum >> 16);
|
checksum = (checksum & 0xffff) | (checksum >> 16);
|
||||||
count -= 2;
|
count -= 2;
|
||||||
}
|
}
|
||||||
while (checksum >> 16)
|
while (checksum >> 16)
|
||||||
checksum = (checksum & 0xffff) + (checksum >> 16);
|
checksum = (checksum & 0xffff) + (checksum >> 16);
|
||||||
return ~checksum & 0xffff;
|
return htons(~checksum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void timersub(struct timeval* a, struct timeval* b, struct timeval* result)
|
||||||
|
{
|
||||||
|
result->tv_sec = a->tv_sec - b->tv_sec;
|
||||||
|
result->tv_usec = a->tv_usec - b->tv_usec;
|
||||||
|
if (result->tv_usec < 0) {
|
||||||
|
--result->tv_sec;
|
||||||
|
result->tv_usec += 1000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
@ -30,42 +39,82 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* addr_str = "192.168.5.1";
|
||||||
|
if (argc > 1)
|
||||||
|
addr_str = argv[1];
|
||||||
|
|
||||||
|
pid_t pid = getpid();
|
||||||
|
|
||||||
sockaddr_in peer_address;
|
sockaddr_in peer_address;
|
||||||
memset(&peer_address, 0, sizeof(peer_address));
|
memset(&peer_address, 0, sizeof(peer_address));
|
||||||
peer_address.sin_family = AF_INET;
|
peer_address.sin_family = AF_INET;
|
||||||
peer_address.sin_port = 0;
|
peer_address.sin_port = 0;
|
||||||
peer_address.sin_addr.s_addr = 0x0105a8c0; // 192.168.5.1
|
|
||||||
|
int rc = inet_pton(AF_INET, addr_str, &peer_address.sin_addr);
|
||||||
|
|
||||||
struct PingPacket {
|
struct PingPacket {
|
||||||
struct icmphdr header;
|
struct icmphdr header;
|
||||||
char msg[64 - sizeof(struct icmphdr)];
|
char msg[64 - sizeof(struct icmphdr)];
|
||||||
};
|
};
|
||||||
|
|
||||||
PingPacket ping_packet;
|
uint16_t seq = 1;
|
||||||
PingPacket pong_packet;
|
|
||||||
memset(&ping_packet, 0, sizeof(PingPacket));
|
|
||||||
|
|
||||||
ping_packet.header.type = 8; // Echo request
|
for (;;) {
|
||||||
ping_packet.header.code = 0;
|
PingPacket ping_packet;
|
||||||
ping_packet.header.un.echo.id = htons(getpid());
|
PingPacket pong_packet;
|
||||||
ping_packet.header.un.echo.sequence = htons(1);
|
memset(&ping_packet, 0, sizeof(PingPacket));
|
||||||
strcpy(ping_packet.msg, "Hello there!\n");
|
|
||||||
|
|
||||||
ping_packet.header.checksum = htons(internet_checksum(&ping_packet, sizeof(PingPacket)));
|
ping_packet.header.type = 8; // Echo request
|
||||||
|
ping_packet.header.code = 0;
|
||||||
|
ping_packet.header.un.echo.id = htons(pid);
|
||||||
|
ping_packet.header.un.echo.sequence = htons(seq++);
|
||||||
|
strcpy(ping_packet.msg, "Hello there!\n");
|
||||||
|
|
||||||
int rc = sendto(fd, &ping_packet, sizeof(PingPacket), 0, (const struct sockaddr*)&peer_address, sizeof(sockaddr_in));
|
ping_packet.header.checksum = internet_checksum(&ping_packet, sizeof(PingPacket));
|
||||||
if (rc < 0) {
|
|
||||||
perror("sendto");
|
struct timeval tv_send;
|
||||||
return 1;
|
gettimeofday(&tv_send, nullptr);
|
||||||
|
|
||||||
|
rc = sendto(fd, &ping_packet, sizeof(PingPacket), 0, (const struct sockaddr*)&peer_address, sizeof(sockaddr_in));
|
||||||
|
if (rc < 0) {
|
||||||
|
perror("sendto");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
rc = recvfrom(fd, &pong_packet, sizeof(PingPacket), 0, (const struct sockaddr*)&peer_address, sizeof(sockaddr_in));
|
||||||
|
if (rc < 0) {
|
||||||
|
perror("recvfrom");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pong_packet.header.type != 0)
|
||||||
|
continue;
|
||||||
|
if (pong_packet.header.code != 0)
|
||||||
|
continue;
|
||||||
|
if (ntohs(pong_packet.header.un.echo.id) != pid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
struct timeval tv_receive;
|
||||||
|
gettimeofday(&tv_receive, nullptr);
|
||||||
|
|
||||||
|
struct timeval tv_diff;
|
||||||
|
timersub(&tv_receive, &tv_send, &tv_diff);
|
||||||
|
|
||||||
|
int ms = tv_diff.tv_sec * 1000 + tv_diff.tv_usec / 1000;
|
||||||
|
|
||||||
|
char addr_buf[64];
|
||||||
|
printf("Pong from %s: id=%u, seq=%u, time=%dms\n",
|
||||||
|
inet_ntop(AF_INET, &peer_address.sin_addr, addr_buf, sizeof(addr_buf)),
|
||||||
|
ntohs(pong_packet.header.un.echo.id),
|
||||||
|
ntohs(pong_packet.header.un.echo.sequence),
|
||||||
|
ms
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = recvfrom(fd, &pong_packet, sizeof(PingPacket), 0, (const struct sockaddr*)&peer_address, sizeof(sockaddr_in));
|
|
||||||
if (rc < 0) {
|
|
||||||
perror("recvfrom");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("received %p (%d)\n", &pong_packet, rc);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue