diff --git a/Kernel/IPv4Socket.cpp b/Kernel/IPv4Socket.cpp index 239cf3edd3..9e0cec8882 100644 --- a/Kernel/IPv4Socket.cpp +++ b/Kernel/IPv4Socket.cpp @@ -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); +#ifdef IPV4_SOCKET_DEBUG kprintf("recvfrom: peer_address=%s\n", peer_address.to_string().characters()); +#endif ByteBuffer packet_buffer; - { LOCKER(m_lock); if (!m_receive_queue.is_empty()) { 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()) { @@ -163,7 +164,7 @@ ssize_t IPv4Socket::recvfrom(void* buffer, size_t buffer_length, int flags, cons ASSERT(m_can_read); ASSERT(!m_receive_queue.is_empty()); 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()); 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) { +#ifdef IPV4_SOCKET_DEBUG + kprintf("IPv4Socket(%p): did_receive %d bytes\n", this, packet.size()); +#endif LOCKER(m_lock); - kprintf("IPv4Socket(%p): did_receive %d bytes\n", packet.size()); m_receive_queue.append(move(packet)); m_can_read = true; } diff --git a/Kernel/run b/Kernel/run index 152539c1eb..a3b56265be 100755 --- a/Kernel/run +++ b/Kernel/run @@ -6,9 +6,11 @@ if [ "$1" = "b" ]; then elif [ "$1" = "qn" ]; then # ./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 #$@ -else - echo run with net - # ./run: qemu with network +elif [ "$1" = "qtap" ]; then + # ./run qtap: qemu with tap 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 diff --git a/Kernel/types.h b/Kernel/types.h index efa5a31977..5f517a7736 100644 --- a/Kernel/types.h +++ b/Kernel/types.h @@ -13,7 +13,7 @@ typedef dword gid_t; typedef signed_word pid_t; typedef dword time_t; typedef dword useconds_t; -typedef dword suseconds_t; +typedef signed_dword suseconds_t; struct timeval { time_t tv_sec; diff --git a/LibC/arpa/inet.cpp b/LibC/arpa/inet.cpp index f4806609e9..a85ee697a7 100644 --- a/LibC/arpa/inet.cpp +++ b/LibC/arpa/inet.cpp @@ -11,9 +11,41 @@ const char* inet_ntop(int af, const void* src, char* dst, socklen_t len) return nullptr; } 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; } +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; +} + } diff --git a/LibC/arpa/inet.h b/LibC/arpa/inet.h index 8e913233bd..7f3a8804e1 100644 --- a/LibC/arpa/inet.h +++ b/LibC/arpa/inet.h @@ -6,6 +6,7 @@ __BEGIN_DECLS 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) { diff --git a/LibC/sys/types.h b/LibC/sys/types.h index 442387379a..dc6f1530ea 100644 --- a/LibC/sys/types.h +++ b/LibC/sys/types.h @@ -30,7 +30,7 @@ typedef uint32_t blksize_t; typedef uint32_t blkcnt_t; typedef uint32_t time_t; typedef uint32_t useconds_t; -typedef uint32_t suseconds_t; +typedef int32_t suseconds_t; typedef uint32_t clock_t; typedef uint32_t socklen_t; diff --git a/Userland/ping.cpp b/Userland/ping.cpp index b35258e1a4..b39855cab2 100644 --- a/Userland/ping.cpp +++ b/Userland/ping.cpp @@ -4,23 +4,32 @@ #include #include #include -#include +#include -NetworkOrdered internet_checksum(const void* ptr, size_t count) +uint16_t internet_checksum(const void* ptr, size_t count) { - dword checksum = 0; - auto* w = (const word*)ptr; + uint32_t checksum = 0; + auto* w = (const uint16_t*)ptr; while (count > 1) { - checksum += convert_between_host_and_network(*w++); + checksum += ntohs(*w++); if (checksum & 0x80000000) checksum = (checksum & 0xffff) | (checksum >> 16); count -= 2; } while (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) { @@ -30,42 +39,82 @@ int main(int argc, char** argv) 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; memset(&peer_address, 0, sizeof(peer_address)); peer_address.sin_family = AF_INET; 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 icmphdr header; char msg[64 - sizeof(struct icmphdr)]; }; - PingPacket ping_packet; - PingPacket pong_packet; - memset(&ping_packet, 0, sizeof(PingPacket)); + uint16_t seq = 1; - ping_packet.header.type = 8; // Echo request - ping_packet.header.code = 0; - ping_packet.header.un.echo.id = htons(getpid()); - ping_packet.header.un.echo.sequence = htons(1); - strcpy(ping_packet.msg, "Hello there!\n"); + for (;;) { + PingPacket ping_packet; + PingPacket pong_packet; + memset(&ping_packet, 0, sizeof(PingPacket)); - 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)); - if (rc < 0) { - perror("sendto"); - return 1; + ping_packet.header.checksum = internet_checksum(&ping_packet, sizeof(PingPacket)); + + struct timeval tv_send; + 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; }