Browse Source

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.
Andreas Kling 6 years ago
parent
commit
cf250e1245
7 changed files with 124 additions and 37 deletions
  1. 7 4
      Kernel/IPv4Socket.cpp
  2. 5 3
      Kernel/run
  3. 1 1
      Kernel/types.h
  4. 33 1
      LibC/arpa/inet.cpp
  5. 1 0
      LibC/arpa/inet.h
  6. 1 1
      LibC/sys/types.h
  7. 76 27
      Userland/ping.cpp

+ 7 - 4
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;
 }

+ 5 - 3
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
 

+ 1 - 1
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;

+ 33 - 1
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;
+}
+
 }
 

+ 1 - 0
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)
 {

+ 1 - 1
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;
 

+ 76 - 27
Userland/ping.cpp

@@ -4,23 +4,32 @@
 #include <stdio.h>
 #include <string.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;
-    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));
 
-    rc = recvfrom(fd, &pong_packet, sizeof(PingPacket), 0, (const struct sockaddr*)&peer_address, sizeof(sockaddr_in));
-    if (rc < 0) {
-        perror("recvfrom");
-        return 1;
-    }
+        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);
 
-    printf("received %p (%d)\n", &pong_packet, rc);
+            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);
+    }
 
     return 0;
 }