mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 15:40:19 +00:00
Kernel+LibC+Userland: Start working on an IPv4 socket backend.
The first userland networking program will be "ping" :^)
This commit is contained in:
parent
8e667747f0
commit
a017a77442
Notes:
sideshowbarker
2024-07-19 15:04:40 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/a017a774427
23 changed files with 374 additions and 3 deletions
|
@ -28,7 +28,6 @@ public:
|
|||
m_data[2] = c;
|
||||
m_data[3] = d;
|
||||
}
|
||||
~IPv4Address() { }
|
||||
|
||||
byte operator[](int i) const
|
||||
{
|
||||
|
|
111
Kernel/IPv4Socket.cpp
Normal file
111
Kernel/IPv4Socket.cpp
Normal file
|
@ -0,0 +1,111 @@
|
|||
#include <Kernel/IPv4Socket.h>
|
||||
#include <Kernel/UnixTypes.h>
|
||||
#include <Kernel/Process.h>
|
||||
#include <Kernel/NetworkAdapter.h>
|
||||
#include <LibC/errno_numbers.h>
|
||||
|
||||
Retained<IPv4Socket> IPv4Socket::create(int type, int protocol)
|
||||
{
|
||||
return adopt(*new IPv4Socket(type, protocol));
|
||||
}
|
||||
|
||||
IPv4Socket::IPv4Socket(int type, int protocol)
|
||||
: Socket(AF_INET, type, protocol)
|
||||
{
|
||||
kprintf("%s(%u) IPv4Socket{%p} created with type=%u\n", current->name().characters(), current->pid(), this, type);
|
||||
}
|
||||
|
||||
IPv4Socket::~IPv4Socket()
|
||||
{
|
||||
}
|
||||
|
||||
bool IPv4Socket::get_address(sockaddr* address, socklen_t* address_size)
|
||||
{
|
||||
// FIXME: Look into what fallback behavior we should have here.
|
||||
if (*address_size != sizeof(sockaddr_in))
|
||||
return false;
|
||||
memcpy(address, &m_peer_address, sizeof(sockaddr_in));
|
||||
*address_size = sizeof(sockaddr_in);
|
||||
return true;
|
||||
}
|
||||
|
||||
KResult IPv4Socket::bind(const sockaddr* address, socklen_t address_size)
|
||||
{
|
||||
ASSERT(!is_connected());
|
||||
if (address_size != sizeof(sockaddr_in))
|
||||
return KResult(-EINVAL);
|
||||
if (address->sa_family != AF_INET)
|
||||
return KResult(-EINVAL);
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
KResult IPv4Socket::connect(const sockaddr* address, socklen_t address_size)
|
||||
{
|
||||
ASSERT(!m_bound);
|
||||
if (address_size != sizeof(sockaddr_in))
|
||||
return KResult(-EINVAL);
|
||||
if (address->sa_family != AF_INET)
|
||||
return KResult(-EINVAL);
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void IPv4Socket::attach_fd(SocketRole)
|
||||
{
|
||||
++m_attached_fds;
|
||||
}
|
||||
|
||||
void IPv4Socket::detach_fd(SocketRole)
|
||||
{
|
||||
--m_attached_fds;
|
||||
}
|
||||
|
||||
bool IPv4Socket::can_read(SocketRole) const
|
||||
{
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
ssize_t IPv4Socket::read(SocketRole role, byte* buffer, ssize_t size)
|
||||
{
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
ssize_t IPv4Socket::write(SocketRole role, const byte* data, ssize_t size)
|
||||
{
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
bool IPv4Socket::can_write(SocketRole role) const
|
||||
{
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
ssize_t IPv4Socket::sendto(const void* data, size_t data_length, int flags, const sockaddr* addr, socklen_t addr_length)
|
||||
{
|
||||
(void)flags;
|
||||
ASSERT(data_length);
|
||||
if (addr_length != sizeof(sockaddr_in))
|
||||
return -EINVAL;
|
||||
// FIXME: Find the adapter some better way!
|
||||
auto* adapter = NetworkAdapter::from_ipv4_address(IPv4Address(192, 168, 5, 2));
|
||||
if (!adapter) {
|
||||
// FIXME: Figure out which error code to return.
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
if (addr->sa_family != AF_INET) {
|
||||
kprintf("sendto: Bad address family: %u is not AF_INET!\n", addr->sa_family);
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
auto peer_address = IPv4Address((const byte*)&((const sockaddr_in*)addr)->sin_addr.s_addr);
|
||||
|
||||
kprintf("sendto: peer_address=%s\n", peer_address.to_string().characters());
|
||||
|
||||
// FIXME: If we can't find the right MAC address, block until it's available?
|
||||
// I feel like this should happen in a layer below this code.
|
||||
MACAddress mac_address;
|
||||
adapter->send_ipv4(mac_address, peer_address, (IPv4Protocol)protocol(), ByteBuffer::copy((const byte*)data, data_length));
|
||||
return data_length;
|
||||
}
|
34
Kernel/IPv4Socket.h
Normal file
34
Kernel/IPv4Socket.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
|
||||
#include <Kernel/Socket.h>
|
||||
#include <Kernel/DoubleBuffer.h>
|
||||
#include <Kernel/IPv4.h>
|
||||
|
||||
class IPv4Socket final : public Socket {
|
||||
public:
|
||||
static Retained<IPv4Socket> create(int type, int protocol);
|
||||
virtual ~IPv4Socket() override;
|
||||
|
||||
virtual KResult bind(const sockaddr*, socklen_t) override;
|
||||
virtual KResult connect(const sockaddr*, socklen_t) override;
|
||||
virtual bool get_address(sockaddr*, socklen_t*) override;
|
||||
virtual void attach_fd(SocketRole) override;
|
||||
virtual void detach_fd(SocketRole) override;
|
||||
virtual bool can_read(SocketRole) const override;
|
||||
virtual ssize_t read(SocketRole, byte*, ssize_t) override;
|
||||
virtual ssize_t write(SocketRole, const byte*, ssize_t) override;
|
||||
virtual bool can_write(SocketRole) const override;
|
||||
virtual ssize_t sendto(const void*, size_t, int, const sockaddr*, socklen_t) override;
|
||||
|
||||
private:
|
||||
IPv4Socket(int type, int protocol);
|
||||
virtual bool is_ipv4() const override { return true; }
|
||||
|
||||
bool m_bound { false };
|
||||
int m_attached_fds { 0 };
|
||||
IPv4Address m_peer_address;
|
||||
|
||||
DoubleBuffer m_for_client;
|
||||
DoubleBuffer m_for_server;
|
||||
};
|
||||
|
|
@ -163,3 +163,8 @@ bool LocalSocket::can_write(SocketRole role) const
|
|||
return !m_accepted_fds_open || m_for_server.bytes_in_write_buffer() < 4096;
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
ssize_t LocalSocket::sendto(const void*, size_t, int, const sockaddr*, socklen_t)
|
||||
{
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ public:
|
|||
virtual ssize_t read(SocketRole, byte*, ssize_t) override;
|
||||
virtual ssize_t write(SocketRole, const byte*, ssize_t) override;
|
||||
virtual bool can_write(SocketRole) const override;
|
||||
virtual ssize_t sendto(const void*, size_t, int, const sockaddr*, socklen_t) override;
|
||||
|
||||
private:
|
||||
explicit LocalSocket(int type);
|
||||
|
|
|
@ -34,6 +34,7 @@ KERNEL_OBJS = \
|
|||
PS2MouseDevice.o \
|
||||
Socket.o \
|
||||
LocalSocket.o \
|
||||
IPv4Socket.o \
|
||||
NetworkAdapter.o \
|
||||
E1000NetworkAdapter.o \
|
||||
NetworkTask.o
|
||||
|
|
|
@ -2515,6 +2515,32 @@ KResult Process::wait_for_connect(Socket& socket)
|
|||
return KSuccess;
|
||||
}
|
||||
|
||||
ssize_t Process::sys$sendto(const Syscall::SC_sendto_params* params)
|
||||
{
|
||||
if (!validate_read_typed(params))
|
||||
return -EFAULT;
|
||||
|
||||
int sockfd = params->sockfd;
|
||||
const void* data = params->data;
|
||||
size_t data_length = params->data_length;
|
||||
int flags = params->flags;
|
||||
auto* addr = (const sockaddr*)params->addr;
|
||||
auto addr_length = (socklen_t)params->addr_length;
|
||||
|
||||
if (!validate_read(data, data_length))
|
||||
return -EFAULT;
|
||||
if (!validate_read(addr, addr_length))
|
||||
return -EFAULT;
|
||||
auto* descriptor = file_descriptor(sockfd);
|
||||
if (!descriptor)
|
||||
return -EBADF;
|
||||
if (!descriptor->is_socket())
|
||||
return -ENOTSOCK;
|
||||
auto& socket = *descriptor->socket();
|
||||
kprintf("sendto %p (%u), flags=%u, addr: %p (%u)\n", data, data_length, flags, addr, addr_length);
|
||||
return socket.sendto(data, data_length, flags, addr, addr_length);
|
||||
}
|
||||
|
||||
struct SharedBuffer {
|
||||
SharedBuffer(pid_t pid1, pid_t pid2, int size)
|
||||
: m_pid1(pid1)
|
||||
|
|
|
@ -230,6 +230,7 @@ public:
|
|||
int sys$listen(int sockfd, int backlog);
|
||||
int sys$accept(int sockfd, sockaddr*, socklen_t*);
|
||||
int sys$connect(int sockfd, const sockaddr*, socklen_t);
|
||||
ssize_t sys$sendto(const Syscall::SC_sendto_params*);
|
||||
int sys$restore_signal_mask(dword mask);
|
||||
|
||||
int sys$create_shared_buffer(pid_t peer_pid, int, void** buffer);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <Kernel/Socket.h>
|
||||
#include <Kernel/LocalSocket.h>
|
||||
#include <Kernel/IPv4Socket.h>
|
||||
#include <Kernel/UnixTypes.h>
|
||||
#include <Kernel/Process.h>
|
||||
#include <LibC/errno_numbers.h>
|
||||
|
@ -10,6 +11,8 @@ KResultOr<Retained<Socket>> Socket::create(int domain, int type, int protocol)
|
|||
switch (domain) {
|
||||
case AF_LOCAL:
|
||||
return LocalSocket::create(type & SOCK_TYPE_MASK);
|
||||
case AF_INET:
|
||||
return IPv4Socket::create(type & SOCK_TYPE_MASK, protocol);
|
||||
default:
|
||||
return KResult(-EAFNOSUPPORT);
|
||||
}
|
||||
|
|
|
@ -28,12 +28,14 @@ public:
|
|||
virtual KResult connect(const sockaddr*, socklen_t) = 0;
|
||||
virtual bool get_address(sockaddr*, socklen_t*) = 0;
|
||||
virtual bool is_local() const { return false; }
|
||||
virtual bool is_ipv4() const { return false; }
|
||||
virtual void attach_fd(SocketRole) = 0;
|
||||
virtual void detach_fd(SocketRole) = 0;
|
||||
virtual bool can_read(SocketRole) const = 0;
|
||||
virtual ssize_t read(SocketRole, byte*, ssize_t) = 0;
|
||||
virtual ssize_t write(SocketRole, const byte*, ssize_t) = 0;
|
||||
virtual bool can_write(SocketRole) const = 0;
|
||||
virtual ssize_t sendto(const void*, size_t, int flags, const sockaddr*, socklen_t) = 0;
|
||||
|
||||
pid_t origin_pid() const { return m_origin_pid; }
|
||||
|
||||
|
|
|
@ -227,6 +227,8 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2,
|
|||
return current->sys$seal_shared_buffer((int)arg1);
|
||||
case Syscall::SC_get_shared_buffer_size:
|
||||
return current->sys$get_shared_buffer_size((int)arg1);
|
||||
case Syscall::SC_sendto:
|
||||
return current->sys$sendto((const SC_sendto_params*)arg1);
|
||||
default:
|
||||
kprintf("<%u> int0x82: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3);
|
||||
break;
|
||||
|
|
|
@ -88,6 +88,7 @@
|
|||
__ENUMERATE_SYSCALL(restore_signal_mask) \
|
||||
__ENUMERATE_SYSCALL(get_shared_buffer_size) \
|
||||
__ENUMERATE_SYSCALL(seal_shared_buffer) \
|
||||
__ENUMERATE_SYSCALL(sendto) \
|
||||
|
||||
|
||||
namespace Syscall {
|
||||
|
@ -128,6 +129,15 @@ struct SC_select_params {
|
|||
struct timeval* timeout;
|
||||
};
|
||||
|
||||
struct SC_sendto_params {
|
||||
int sockfd;
|
||||
const void* data;
|
||||
size_t data_length;
|
||||
int flags;
|
||||
const void* addr; // const sockaddr*
|
||||
size_t addr_length; // socklen_t
|
||||
};
|
||||
|
||||
void initialize();
|
||||
int sync();
|
||||
|
||||
|
|
|
@ -315,12 +315,20 @@ struct pollfd {
|
|||
#define AF_MASK 0xff
|
||||
#define AF_UNSPEC 0
|
||||
#define AF_LOCAL 1
|
||||
#define AF_INET 2
|
||||
#define PF_LOCAL AF_LOCAL
|
||||
#define PF_INET AF_INET
|
||||
|
||||
#define SOCK_TYPE_MASK 0xff
|
||||
#define SOCK_STREAM 1
|
||||
#define SOCK_RAW 3
|
||||
#define SOCK_NONBLOCK 04000
|
||||
#define SOCK_CLOEXEC 02000000
|
||||
|
||||
#define IPPROTO_ICMP 1
|
||||
#define IPPROTO_TCP 6
|
||||
#define IPPROTO_UDP 17
|
||||
|
||||
struct sockaddr {
|
||||
word sa_family;
|
||||
char sa_data[14];
|
||||
|
@ -333,3 +341,14 @@ struct sockaddr_un {
|
|||
word sun_family;
|
||||
char sun_path[UNIX_PATH_MAX];
|
||||
};
|
||||
|
||||
struct in_addr {
|
||||
uint32_t s_addr;
|
||||
};
|
||||
|
||||
struct sockaddr_in {
|
||||
int16_t sin_family;
|
||||
uint16_t sin_port;
|
||||
struct in_addr sin_addr;
|
||||
char sin_zero[8];
|
||||
};
|
||||
|
|
|
@ -74,6 +74,7 @@ cp -v ../Userland/df mnt/bin/df
|
|||
cp -v ../Userland/su mnt/bin/su
|
||||
cp -v ../Userland/env mnt/bin/env
|
||||
cp -v ../Userland/stat mnt/bin/stat
|
||||
cp -v ../Userland/ping mnt/bin/ping
|
||||
chmod 4755 mnt/bin/su
|
||||
cp -v ../Applications/Terminal/Terminal mnt/bin/Terminal
|
||||
cp -v ../Applications/FontEditor/FontEditor mnt/bin/FontEditor
|
||||
|
|
|
@ -39,6 +39,7 @@ LIBC_OBJS = \
|
|||
sys/wait.o \
|
||||
poll.o \
|
||||
locale.o \
|
||||
arpa/inet.o \
|
||||
crt0.o
|
||||
|
||||
ASM_OBJS = setjmp.no
|
||||
|
|
19
LibC/arpa/inet.cpp
Normal file
19
LibC/arpa/inet.cpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
const char* inet_ntop(int af, const void* src, char* dst, socklen_t len)
|
||||
{
|
||||
if (af != AF_INET) {
|
||||
errno = EAFNOSUPPORT;
|
||||
return nullptr;
|
||||
}
|
||||
auto* bytes = (const unsigned char*)src;
|
||||
snprintf(dst, len, "%u.%u.%u.%u", bytes[3], bytes[2], bytes[1], bytes[0]);
|
||||
return (const char*)dst;
|
||||
}
|
||||
|
||||
}
|
||||
|
22
LibC/arpa/inet.h
Normal file
22
LibC/arpa/inet.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
const char* inet_ntop(int af, const void* src, char* dst, socklen_t);
|
||||
|
||||
static inline uint16_t htons(uint16_t hs)
|
||||
{
|
||||
uint8_t* s = (uint8_t*)&hs;
|
||||
return (uint16_t)(s[0] << 8 | s[1]);
|
||||
}
|
||||
|
||||
static inline uint16_t ntohs(uint16_t ns)
|
||||
{
|
||||
return htons(ns);
|
||||
}
|
||||
|
||||
__END_DECLS
|
||||
|
22
LibC/netinet/ip_icmp.h
Normal file
22
LibC/netinet/ip_icmp.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <stdint.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
struct icmphdr {
|
||||
uint8_t type;
|
||||
uint8_t code;
|
||||
uint16_t checksum;
|
||||
union {
|
||||
struct {
|
||||
uint16_t id;
|
||||
uint16_t sequence;
|
||||
} echo;
|
||||
uint32_t gateway;
|
||||
} un;
|
||||
};
|
||||
|
||||
__END_DECLS
|
||||
|
|
@ -34,5 +34,12 @@ int connect(int sockfd, const sockaddr* addr, socklen_t addrlen)
|
|||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
ssize_t sendto(int sockfd, const void* data, size_t data_length, int flags, const struct sockaddr* addr, socklen_t addr_length)
|
||||
{
|
||||
Syscall::SC_sendto_params params { sockfd, data, data_length, flags, addr, addr_length };
|
||||
int rc = syscall(SC_sendto, ¶ms);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -2,34 +2,55 @@
|
|||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define AF_MASK 0xff
|
||||
#define AF_UNSPEC 0
|
||||
#define AF_LOCAL 1
|
||||
#define AF_INET 2
|
||||
#define PF_LOCAL AF_LOCAL
|
||||
#define PF_INET AF_INET
|
||||
|
||||
#define SOCK_TYPE_MASK 0xff
|
||||
#define SOCK_STREAM 1
|
||||
#define SOCK_RAW 3
|
||||
#define SOCK_NONBLOCK 04000
|
||||
#define SOCK_CLOEXEC 02000000
|
||||
|
||||
#define IPPROTO_ICMP 1
|
||||
#define IPPROTO_TCP 6
|
||||
#define IPPROTO_UDP 17
|
||||
|
||||
struct sockaddr {
|
||||
unsigned short sa_family;
|
||||
uint16_t sa_family;
|
||||
char sa_data[14];
|
||||
};
|
||||
|
||||
#define UNIX_PATH_MAX 108
|
||||
struct sockaddr_un {
|
||||
unsigned short sun_family;
|
||||
uint16_t sun_family;
|
||||
char sun_path[UNIX_PATH_MAX];
|
||||
};
|
||||
|
||||
struct in_addr {
|
||||
uint32_t s_addr;
|
||||
};
|
||||
|
||||
struct sockaddr_in {
|
||||
uint16_t sin_family;
|
||||
uint16_t sin_port;
|
||||
struct in_addr sin_addr;
|
||||
char sin_zero[8];
|
||||
};
|
||||
|
||||
int socket(int domain, int type, int protocol);
|
||||
int bind(int sockfd, const sockaddr* addr, socklen_t);
|
||||
int listen(int sockfd, int backlog);
|
||||
int accept(int sockfd, sockaddr*, socklen_t*);
|
||||
int connect(int sockfd, const sockaddr*, socklen_t);
|
||||
ssize_t sendto(int sockfd, const void*, size_t, int flags, const struct sockaddr*, socklen_t);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
|
1
Userland/.gitignore
vendored
1
Userland/.gitignore
vendored
|
@ -37,3 +37,4 @@ su
|
|||
env
|
||||
chown
|
||||
stat
|
||||
ping
|
||||
|
|
|
@ -33,6 +33,7 @@ OBJS = \
|
|||
su.o \
|
||||
env.o \
|
||||
stat.o \
|
||||
ping.o \
|
||||
rm.o
|
||||
|
||||
APPS = \
|
||||
|
@ -71,6 +72,7 @@ APPS = \
|
|||
su \
|
||||
env \
|
||||
stat \
|
||||
ping \
|
||||
rm
|
||||
|
||||
ARCH_FLAGS =
|
||||
|
@ -198,6 +200,9 @@ env: env.o
|
|||
stat: stat.o
|
||||
$(LD) -o $@ $(LDFLAGS) $< -lc
|
||||
|
||||
ping: ping.o
|
||||
$(LD) -o $@ $(LDFLAGS) $< -lc
|
||||
|
||||
.cpp.o:
|
||||
@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
|
||||
|
||||
|
|
58
Userland/ping.cpp
Normal file
58
Userland/ping.cpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/ip_icmp.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <Kernel/NetworkOrdered.h>
|
||||
|
||||
NetworkOrdered<word> internet_checksum(const void* ptr, size_t count)
|
||||
{
|
||||
dword checksum = 0;
|
||||
auto* w = (const word*)ptr;
|
||||
while (count > 1) {
|
||||
checksum += convert_between_host_and_network(*w++);
|
||||
if (checksum & 0x80000000)
|
||||
checksum = (checksum & 0xffff) | (checksum >> 16);
|
||||
count -= 2;
|
||||
}
|
||||
while (checksum >> 16)
|
||||
checksum = (checksum & 0xffff) + (checksum >> 16);
|
||||
return ~checksum & 0xffff;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
|
||||
if (fd < 0) {
|
||||
perror("socket");
|
||||
return 1;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
struct PingPacket {
|
||||
struct icmphdr header;
|
||||
char msg[64 - sizeof(struct icmphdr)];
|
||||
};
|
||||
|
||||
PingPacket ping_packet;
|
||||
memset(&ping_packet, 0, sizeof(PingPacket));
|
||||
|
||||
ping_packet.header.type = 8; // Echo request
|
||||
strcpy(ping_packet.msg, "Hello there!\n");
|
||||
|
||||
ping_packet.header.checksum = htons(internet_checksum(&ping_packet, sizeof(PingPacket)));
|
||||
|
||||
int rc = sendto(fd, &ping_packet, sizeof(PingPacket), 0, (const struct sockaddr*)&peer_address, sizeof(sockaddr_in));
|
||||
if (rc < 0) {
|
||||
perror("sendto");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue