mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 22:57:44 +00:00
Add support for socket send/receive timeouts.
Only the receive timeout is hooked up yet. You can change the timeout by calling setsockopt(..., SOL_SOCKET, SO_RCVTIMEO, ...). Use this mechanism to make /bin/ping report timeouts.
This commit is contained in:
parent
7bcd386338
commit
562663df7c
12 changed files with 212 additions and 12 deletions
|
@ -157,10 +157,15 @@ ssize_t IPv4Socket::recvfrom(void* buffer, size_t buffer_length, int flags, cons
|
||||||
}
|
}
|
||||||
if (packet_buffer.is_null()) {
|
if (packet_buffer.is_null()) {
|
||||||
current->set_blocked_socket(this);
|
current->set_blocked_socket(this);
|
||||||
|
load_receive_deadline();
|
||||||
block(Process::BlockedReceive);
|
block(Process::BlockedReceive);
|
||||||
Scheduler::yield();
|
Scheduler::yield();
|
||||||
|
|
||||||
LOCKER(m_lock);
|
LOCKER(m_lock);
|
||||||
|
if (!m_can_read) {
|
||||||
|
// Unblocked due to timeout.
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
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();
|
||||||
|
@ -175,10 +180,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);
|
||||||
m_receive_queue.append(move(packet));
|
m_receive_queue.append(move(packet));
|
||||||
m_can_read = true;
|
m_can_read = true;
|
||||||
|
#ifdef IPV4_SOCKET_DEBUG
|
||||||
|
kprintf("IPv4Socket(%p): did_receive %d bytes, packets in queue: %d\n", this, packet.size(), m_receive_queue.size_slow());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -1589,13 +1589,17 @@ int Process::sys$sleep(unsigned seconds)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void kgettimeofday(timeval& tv)
|
||||||
|
{
|
||||||
|
tv.tv_sec = RTC::now();
|
||||||
|
tv.tv_usec = (PIT::ticks_since_boot() % 1000) * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
int Process::sys$gettimeofday(timeval* tv)
|
int Process::sys$gettimeofday(timeval* tv)
|
||||||
{
|
{
|
||||||
if (!validate_write_typed(tv))
|
if (!validate_write_typed(tv))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
auto now = RTC::now();
|
kgettimeofday(*tv);
|
||||||
tv->tv_sec = now;
|
|
||||||
tv->tv_usec = (PIT::ticks_since_boot() % 1000) * 1000;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2567,6 +2571,50 @@ ssize_t Process::sys$recvfrom(const Syscall::SC_recvfrom_params* params)
|
||||||
return socket.recvfrom(buffer, buffer_length, flags, addr, addr_length);
|
return socket.recvfrom(buffer, buffer_length, flags, addr, addr_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Process::sys$getsockopt(const Syscall::SC_getsockopt_params* params)
|
||||||
|
{
|
||||||
|
if (!validate_read_typed(params))
|
||||||
|
return -EFAULT;
|
||||||
|
int sockfd = params->sockfd;
|
||||||
|
int level = params->level;
|
||||||
|
int option = params->option;
|
||||||
|
auto* value = params->value;
|
||||||
|
auto* value_size = (socklen_t*)params->value_size;
|
||||||
|
|
||||||
|
if (!validate_write_typed(value_size))
|
||||||
|
return -EFAULT;
|
||||||
|
if (!validate_write(value, *value_size))
|
||||||
|
return -EFAULT;
|
||||||
|
auto* descriptor = file_descriptor(sockfd);
|
||||||
|
if (!descriptor)
|
||||||
|
return -EBADF;
|
||||||
|
if (!descriptor->is_socket())
|
||||||
|
return -ENOTSOCK;
|
||||||
|
auto& socket = *descriptor->socket();
|
||||||
|
return socket.getsockopt(level, option, value, value_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Process::sys$setsockopt(const Syscall::SC_setsockopt_params* params)
|
||||||
|
{
|
||||||
|
if (!validate_read_typed(params))
|
||||||
|
return -EFAULT;
|
||||||
|
int sockfd = params->sockfd;
|
||||||
|
int level = params->level;
|
||||||
|
int option = params->option;
|
||||||
|
auto* value = params->value;
|
||||||
|
auto value_size = (socklen_t)params->value_size;
|
||||||
|
|
||||||
|
if (!validate_read(value, value_size))
|
||||||
|
return -EFAULT;
|
||||||
|
auto* descriptor = file_descriptor(sockfd);
|
||||||
|
if (!descriptor)
|
||||||
|
return -EBADF;
|
||||||
|
if (!descriptor->is_socket())
|
||||||
|
return -ENOTSOCK;
|
||||||
|
auto& socket = *descriptor->socket();
|
||||||
|
return socket.setsockopt(level, option, value, value_size);
|
||||||
|
}
|
||||||
|
|
||||||
struct SharedBuffer {
|
struct SharedBuffer {
|
||||||
SharedBuffer(pid_t pid1, pid_t pid2, int size)
|
SharedBuffer(pid_t pid1, pid_t pid2, int size)
|
||||||
: m_pid1(pid1)
|
: m_pid1(pid1)
|
||||||
|
|
|
@ -46,6 +46,8 @@ struct DisplayInfo {
|
||||||
unsigned pitch;
|
unsigned pitch;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void kgettimeofday(timeval&);
|
||||||
|
|
||||||
class Process : public InlineLinkedListNode<Process>, public Weakable<Process> {
|
class Process : public InlineLinkedListNode<Process>, public Weakable<Process> {
|
||||||
friend class InlineLinkedListNode<Process>;
|
friend class InlineLinkedListNode<Process>;
|
||||||
public:
|
public:
|
||||||
|
@ -233,6 +235,8 @@ public:
|
||||||
int sys$connect(int sockfd, const sockaddr*, socklen_t);
|
int sys$connect(int sockfd, const sockaddr*, socklen_t);
|
||||||
ssize_t sys$sendto(const Syscall::SC_sendto_params*);
|
ssize_t sys$sendto(const Syscall::SC_sendto_params*);
|
||||||
ssize_t sys$recvfrom(const Syscall::SC_recvfrom_params*);
|
ssize_t sys$recvfrom(const Syscall::SC_recvfrom_params*);
|
||||||
|
int sys$getsockopt(const Syscall::SC_getsockopt_params*);
|
||||||
|
int sys$setsockopt(const Syscall::SC_setsockopt_params*);
|
||||||
int sys$restore_signal_mask(dword mask);
|
int sys$restore_signal_mask(dword mask);
|
||||||
|
|
||||||
int sys$create_shared_buffer(pid_t peer_pid, int, void** buffer);
|
int sys$create_shared_buffer(pid_t peer_pid, int, void** buffer);
|
||||||
|
|
|
@ -54,8 +54,11 @@ bool Scheduler::pick_next()
|
||||||
return context_switch(*s_colonel_process);
|
return context_switch(*s_colonel_process);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto now_sec = RTC::now();
|
||||||
|
auto now_usec = (suseconds_t)((PIT::ticks_since_boot() % 1000) * 1000);
|
||||||
|
|
||||||
// Check and unblock processes whose wait conditions have been met.
|
// Check and unblock processes whose wait conditions have been met.
|
||||||
Process::for_each([] (Process& process) {
|
Process::for_each([&] (Process& process) {
|
||||||
if (process.state() == Process::BlockedSleep) {
|
if (process.state() == Process::BlockedSleep) {
|
||||||
if (process.wakeup_time() <= system.uptime)
|
if (process.wakeup_time() <= system.uptime)
|
||||||
process.unblock();
|
process.unblock();
|
||||||
|
@ -100,18 +103,19 @@ bool Scheduler::pick_next()
|
||||||
|
|
||||||
if (process.state() == Process::BlockedReceive) {
|
if (process.state() == Process::BlockedReceive) {
|
||||||
ASSERT(process.m_blocked_socket);
|
ASSERT(process.m_blocked_socket);
|
||||||
|
auto& socket = *process.m_blocked_socket;
|
||||||
// FIXME: Block until the amount of data wanted is available.
|
// FIXME: Block until the amount of data wanted is available.
|
||||||
if (process.m_blocked_socket->can_read(SocketRole::None)) {
|
bool timed_out = now_sec > socket.receive_deadline().tv_sec || (now_sec == socket.receive_deadline().tv_sec && now_usec >= socket.receive_deadline().tv_usec);
|
||||||
|
if (timed_out || socket.can_read(SocketRole::None)) {
|
||||||
process.unblock();
|
process.unblock();
|
||||||
process.m_blocked_socket = nullptr;
|
process.m_blocked_socket = nullptr;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.state() == Process::BlockedSelect) {
|
if (process.state() == Process::BlockedSelect) {
|
||||||
if (process.m_select_has_timeout) {
|
if (process.m_select_has_timeout) {
|
||||||
auto now_sec = RTC::now();
|
|
||||||
auto now_usec = PIT::ticks_since_boot() % 1000;
|
|
||||||
if (now_sec > process.m_select_timeout.tv_sec || (now_sec == process.m_select_timeout.tv_sec && now_usec >= process.m_select_timeout.tv_usec)) {
|
if (now_sec > process.m_select_timeout.tv_sec || (now_sec == process.m_select_timeout.tv_sec && now_usec >= process.m_select_timeout.tv_usec)) {
|
||||||
process.unblock();
|
process.unblock();
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -60,3 +60,63 @@ KResult Socket::queue_connection_from(Socket& peer)
|
||||||
m_pending.append(peer);
|
m_pending.append(peer);
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KResult Socket::setsockopt(int level, int option, const void* value, socklen_t value_size)
|
||||||
|
{
|
||||||
|
ASSERT(level == SOL_SOCKET);
|
||||||
|
switch (option) {
|
||||||
|
case SO_SNDTIMEO:
|
||||||
|
if (value_size != sizeof(timeval))
|
||||||
|
return KResult(-EINVAL);
|
||||||
|
m_send_timeout = *(timeval*)value;
|
||||||
|
return KSuccess;
|
||||||
|
case SO_RCVTIMEO:
|
||||||
|
if (value_size != sizeof(timeval))
|
||||||
|
return KResult(-EINVAL);
|
||||||
|
m_receive_timeout = *(timeval*)value;
|
||||||
|
return KSuccess;
|
||||||
|
default:
|
||||||
|
kprintf("%s(%u): setsockopt() at SOL_SOCKET with unimplemented option %d\n", option);
|
||||||
|
return KResult(-ENOPROTOOPT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KResult Socket::getsockopt(int level, int option, void* value, socklen_t* value_size)
|
||||||
|
{
|
||||||
|
ASSERT(level == SOL_SOCKET);
|
||||||
|
switch (option) {
|
||||||
|
case SO_SNDTIMEO:
|
||||||
|
if (*value_size < sizeof(timeval))
|
||||||
|
return KResult(-EINVAL);
|
||||||
|
*(timeval*)value = m_send_timeout;
|
||||||
|
*value_size = sizeof(timeval);
|
||||||
|
return KSuccess;
|
||||||
|
case SO_RCVTIMEO:
|
||||||
|
if (*value_size < sizeof(timeval))
|
||||||
|
return KResult(-EINVAL);
|
||||||
|
*(timeval*)value = m_receive_timeout;
|
||||||
|
*value_size = sizeof(timeval);
|
||||||
|
return KSuccess;
|
||||||
|
default:
|
||||||
|
kprintf("%s(%u): getsockopt() at SOL_SOCKET with unimplemented option %d\n", option);
|
||||||
|
return KResult(-ENOPROTOOPT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Socket::load_receive_deadline()
|
||||||
|
{
|
||||||
|
kgettimeofday(m_receive_deadline);
|
||||||
|
m_receive_deadline.tv_sec += m_receive_timeout.tv_sec;
|
||||||
|
m_receive_deadline.tv_usec += m_receive_timeout.tv_usec;
|
||||||
|
m_receive_deadline.tv_sec += (m_send_timeout.tv_usec / 1000000) * 1;
|
||||||
|
m_receive_deadline.tv_usec %= 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Socket::load_send_deadline()
|
||||||
|
{
|
||||||
|
kgettimeofday(m_send_deadline);
|
||||||
|
m_send_deadline.tv_sec += m_send_timeout.tv_sec;
|
||||||
|
m_send_deadline.tv_usec += m_send_timeout.tv_usec;
|
||||||
|
m_send_deadline.tv_sec += (m_send_timeout.tv_usec / 1000000) * 1;
|
||||||
|
m_send_deadline.tv_usec %= 1000000;
|
||||||
|
}
|
||||||
|
|
|
@ -38,13 +38,22 @@ public:
|
||||||
virtual ssize_t sendto(const void*, size_t, int flags, const sockaddr*, socklen_t) = 0;
|
virtual ssize_t sendto(const void*, size_t, int flags, const sockaddr*, socklen_t) = 0;
|
||||||
virtual ssize_t recvfrom(void*, size_t, int flags, const sockaddr*, socklen_t) = 0;
|
virtual ssize_t recvfrom(void*, size_t, int flags, const sockaddr*, socklen_t) = 0;
|
||||||
|
|
||||||
|
KResult setsockopt(int level, int option, const void*, socklen_t);
|
||||||
|
KResult getsockopt(int level, int option, void*, socklen_t*);
|
||||||
|
|
||||||
pid_t origin_pid() const { return m_origin_pid; }
|
pid_t origin_pid() const { return m_origin_pid; }
|
||||||
|
|
||||||
|
timeval receive_deadline() const { return m_receive_deadline; }
|
||||||
|
timeval send_deadline() const { return m_send_deadline; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Socket(int domain, int type, int protocol);
|
Socket(int domain, int type, int protocol);
|
||||||
|
|
||||||
KResult queue_connection_from(Socket&);
|
KResult queue_connection_from(Socket&);
|
||||||
|
|
||||||
|
void load_receive_deadline();
|
||||||
|
void load_send_deadline();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Lock m_lock;
|
Lock m_lock;
|
||||||
pid_t m_origin_pid { 0 };
|
pid_t m_origin_pid { 0 };
|
||||||
|
@ -54,6 +63,12 @@ private:
|
||||||
int m_backlog { 0 };
|
int m_backlog { 0 };
|
||||||
bool m_connected { false };
|
bool m_connected { false };
|
||||||
|
|
||||||
|
timeval m_receive_timeout { 0, 0 };
|
||||||
|
timeval m_send_timeout { 0, 0 };
|
||||||
|
|
||||||
|
timeval m_receive_deadline { 0, 0 };
|
||||||
|
timeval m_send_deadline { 0, 0 };
|
||||||
|
|
||||||
Vector<RetainPtr<Socket>> m_pending;
|
Vector<RetainPtr<Socket>> m_pending;
|
||||||
Vector<RetainPtr<Socket>> m_clients;
|
Vector<RetainPtr<Socket>> m_clients;
|
||||||
};
|
};
|
||||||
|
|
|
@ -231,6 +231,10 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2,
|
||||||
return current->sys$sendto((const SC_sendto_params*)arg1);
|
return current->sys$sendto((const SC_sendto_params*)arg1);
|
||||||
case Syscall::SC_recvfrom:
|
case Syscall::SC_recvfrom:
|
||||||
return current->sys$recvfrom((const SC_recvfrom_params*)arg1);
|
return current->sys$recvfrom((const SC_recvfrom_params*)arg1);
|
||||||
|
case Syscall::SC_getsockopt:
|
||||||
|
return current->sys$getsockopt((const SC_getsockopt_params*)arg1);
|
||||||
|
case Syscall::SC_setsockopt:
|
||||||
|
return current->sys$setsockopt((const SC_setsockopt_params*)arg1);
|
||||||
default:
|
default:
|
||||||
kprintf("<%u> int0x82: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3);
|
kprintf("<%u> int0x82: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -90,6 +90,8 @@
|
||||||
__ENUMERATE_SYSCALL(seal_shared_buffer) \
|
__ENUMERATE_SYSCALL(seal_shared_buffer) \
|
||||||
__ENUMERATE_SYSCALL(sendto) \
|
__ENUMERATE_SYSCALL(sendto) \
|
||||||
__ENUMERATE_SYSCALL(recvfrom) \
|
__ENUMERATE_SYSCALL(recvfrom) \
|
||||||
|
__ENUMERATE_SYSCALL(getsockopt) \
|
||||||
|
__ENUMERATE_SYSCALL(setsockopt) \
|
||||||
|
|
||||||
|
|
||||||
namespace Syscall {
|
namespace Syscall {
|
||||||
|
@ -148,6 +150,22 @@ struct SC_recvfrom_params {
|
||||||
size_t addr_length; // socklen_t
|
size_t addr_length; // socklen_t
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SC_getsockopt_params {
|
||||||
|
int sockfd;
|
||||||
|
int level;
|
||||||
|
int option;
|
||||||
|
void* value;
|
||||||
|
void* value_size; // socklen_t*
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SC_setsockopt_params {
|
||||||
|
int sockfd;
|
||||||
|
int level;
|
||||||
|
int option;
|
||||||
|
const void* value;
|
||||||
|
size_t value_size; // socklen_t
|
||||||
|
};
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
int sync();
|
int sync();
|
||||||
|
|
||||||
|
|
|
@ -325,6 +325,11 @@ struct pollfd {
|
||||||
#define SOCK_NONBLOCK 04000
|
#define SOCK_NONBLOCK 04000
|
||||||
#define SOCK_CLOEXEC 02000000
|
#define SOCK_CLOEXEC 02000000
|
||||||
|
|
||||||
|
#define SOL_SOCKET 1
|
||||||
|
|
||||||
|
#define SO_RCVTIMEO 1
|
||||||
|
#define SO_SNDTIMEO 2
|
||||||
|
|
||||||
#define IPPROTO_ICMP 1
|
#define IPPROTO_ICMP 1
|
||||||
#define IPPROTO_TCP 6
|
#define IPPROTO_TCP 6
|
||||||
#define IPPROTO_UDP 17
|
#define IPPROTO_UDP 17
|
||||||
|
|
|
@ -48,4 +48,18 @@ ssize_t recvfrom(int sockfd, void* buffer, size_t buffer_length, int flags, cons
|
||||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getsockopt(int sockfd, int level, int option, void* value, socklen_t* value_size)
|
||||||
|
{
|
||||||
|
Syscall::SC_getsockopt_params params { sockfd, level, option, value, value_size };
|
||||||
|
int rc = syscall(SC_getsockopt, ¶ms);
|
||||||
|
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int setsockopt(int sockfd, int level, int option, const void* value, socklen_t value_size)
|
||||||
|
{
|
||||||
|
Syscall::SC_setsockopt_params params { sockfd, level, option, value, value_size };
|
||||||
|
int rc = syscall(SC_setsockopt, ¶ms);
|
||||||
|
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,11 @@ struct sockaddr_in {
|
||||||
char sin_zero[8];
|
char sin_zero[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define SOL_SOCKET 1
|
||||||
|
|
||||||
|
#define SO_RCVTIMEO 1
|
||||||
|
#define SO_SNDTIMEO 2
|
||||||
|
|
||||||
int socket(int domain, int type, int protocol);
|
int socket(int domain, int type, int protocol);
|
||||||
int bind(int sockfd, const sockaddr* addr, socklen_t);
|
int bind(int sockfd, const sockaddr* addr, socklen_t);
|
||||||
int listen(int sockfd, int backlog);
|
int listen(int sockfd, int backlog);
|
||||||
|
@ -52,6 +57,8 @@ int accept(int sockfd, sockaddr*, socklen_t*);
|
||||||
int connect(int sockfd, const 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);
|
ssize_t sendto(int sockfd, const void*, size_t, int flags, const struct sockaddr*, socklen_t);
|
||||||
ssize_t recvfrom(int sockfd, void*, size_t, int flags, const struct sockaddr*, socklen_t);
|
ssize_t recvfrom(int sockfd, void*, size_t, int flags, const struct sockaddr*, socklen_t);
|
||||||
|
int getsockopt(int sockfd, int level, int option, void*, socklen_t*);
|
||||||
|
int setsockopt(int sockfd, int level, int option, const void*, socklen_t);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,13 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct timeval timeout { 1, 0 };
|
||||||
|
int rc = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||||
|
if (rc < 0) {
|
||||||
|
perror("setsockopt");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
const char* addr_str = "192.168.5.1";
|
const char* addr_str = "192.168.5.1";
|
||||||
if (argc > 1)
|
if (argc > 1)
|
||||||
addr_str = argv[1];
|
addr_str = argv[1];
|
||||||
|
@ -50,7 +57,7 @@ int main(int argc, char** argv)
|
||||||
peer_address.sin_family = AF_INET;
|
peer_address.sin_family = AF_INET;
|
||||||
peer_address.sin_port = 0;
|
peer_address.sin_port = 0;
|
||||||
|
|
||||||
int rc = inet_pton(AF_INET, addr_str, &peer_address.sin_addr);
|
rc = inet_pton(AF_INET, addr_str, &peer_address.sin_addr);
|
||||||
|
|
||||||
struct PingPacket {
|
struct PingPacket {
|
||||||
struct icmphdr header;
|
struct icmphdr header;
|
||||||
|
@ -84,6 +91,10 @@ int main(int argc, char** argv)
|
||||||
for (;;) {
|
for (;;) {
|
||||||
rc = recvfrom(fd, &pong_packet, sizeof(PingPacket), 0, (const struct sockaddr*)&peer_address, sizeof(sockaddr_in));
|
rc = recvfrom(fd, &pong_packet, sizeof(PingPacket), 0, (const struct sockaddr*)&peer_address, sizeof(sockaddr_in));
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
|
if (errno == EAGAIN) {
|
||||||
|
printf("Request (seq=%u) timed out.\n", ntohs(ping_packet.header.un.echo.sequence));
|
||||||
|
break;
|
||||||
|
}
|
||||||
perror("recvfrom");
|
perror("recvfrom");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -104,12 +115,17 @@ int main(int argc, char** argv)
|
||||||
int ms = tv_diff.tv_sec * 1000 + tv_diff.tv_usec / 1000;
|
int ms = tv_diff.tv_sec * 1000 + tv_diff.tv_usec / 1000;
|
||||||
|
|
||||||
char addr_buf[64];
|
char addr_buf[64];
|
||||||
printf("Pong from %s: id=%u, seq=%u, time=%dms\n",
|
printf("Pong from %s: id=%u, seq=%u%s, time=%dms\n",
|
||||||
inet_ntop(AF_INET, &peer_address.sin_addr, addr_buf, sizeof(addr_buf)),
|
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.id),
|
||||||
ntohs(pong_packet.header.un.echo.sequence),
|
ntohs(pong_packet.header.un.echo.sequence),
|
||||||
|
pong_packet.header.un.echo.sequence != ping_packet.header.un.echo.sequence ? "(!)" : "",
|
||||||
ms
|
ms
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// If this was a response to an earlier packet, we still need to wait for the current one.
|
||||||
|
if (pong_packet.header.un.echo.sequence != ping_packet.header.un.echo.sequence)
|
||||||
|
continue;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue