1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 19:47:44 +00:00

Kernel+LibC+UserspaceEmulator: Add SO_TIMESTAMP, and cmsg definitions

When SO_TIMESTAMP is set as an option on a SOCK_DGRAM socket, then
recvmsg() will return a SCM_TIMESTAMP control message that
contains a struct timeval with the system time that was current
when the socket was received.
This commit is contained in:
Nico Weber 2020-09-16 12:32:45 -04:00 committed by Andreas Kling
parent ae5ba4074d
commit 47b3e98af8
6 changed files with 94 additions and 2 deletions

View file

@ -133,6 +133,17 @@ KResult Socket::setsockopt(int level, int option, Userspace<const void*> user_va
case SO_KEEPALIVE:
// FIXME: Obviously, this is not a real keepalive.
return KSuccess;
case SO_TIMESTAMP:
if (user_value_size != sizeof(int))
return KResult(-EINVAL);
if (!copy_from_user(&m_timestamp, static_ptr_cast<const int*>(user_value)))
return KResult(-EFAULT);
if (m_timestamp && (domain() != AF_INET || type() == SOCK_STREAM)) {
// FIXME: Support SO_TIMESTAMP for more protocols?
m_timestamp = 0;
return KResult(-ENOTSUP);
}
return KSuccess;
default:
dbg() << "setsockopt(" << option << ") at SOL_SOCKET not implemented.";
return KResult(-ENOPROTOOPT);
@ -196,6 +207,15 @@ KResult Socket::getsockopt(FileDescription&, int level, int option, Userspace<vo
return KResult(-EFAULT);
}
case SO_TIMESTAMP:
if (size < sizeof(int))
return KResult(-EINVAL);
if (!copy_to_user(static_ptr_cast<int*>(value), &m_timestamp))
return KResult(-EFAULT);
size = sizeof(int);
if (!copy_to_user(value_size, &size))
return KResult(-EFAULT);
return KSuccess;
default:
dbg() << "getsockopt(" << option << ") at SOL_SOCKET not implemented.";
return KResult(-ENOPROTOOPT);

View file

@ -135,6 +135,8 @@ public:
bool has_send_timeout() const { return m_send_timeout.tv_sec || m_send_timeout.tv_usec; }
const timeval& send_timeout() const { return m_send_timeout; }
bool wants_timestamp() const { return m_timestamp; }
protected:
Socket(int domain, int type, int protocol);
@ -172,6 +174,7 @@ private:
timeval m_receive_timeout { 0, 0 };
timeval m_send_timeout { 0, 0 };
int m_timestamp { 0 };
NonnullRefPtrVector<Socket> m_pending;
};

View file

@ -264,6 +264,23 @@ ssize_t Process::sys$recvmsg(int sockfd, Userspace<struct msghdr*> user_msg, int
msg_flags |= MSG_TRUNC;
}
if (socket.wants_timestamp()) {
struct {
cmsghdr cmsg;
timeval timestamp;
} cmsg_timestamp;
socklen_t control_length = sizeof(cmsg_timestamp);
if (msg.msg_controllen < control_length) {
msg_flags |= MSG_CTRUNC;
} else {
cmsg_timestamp = { { control_length, SOL_SOCKET, SCM_TIMESTAMP }, timestamp };
if (!copy_to_user(msg.msg_control, &cmsg_timestamp, control_length))
return -EFAULT;
}
if (!copy_to_user(&user_msg.unsafe_userspace_ptr()->msg_controllen, &control_length))
return -EFAULT;
}
if (!copy_to_user(&user_msg.unsafe_userspace_ptr()->msg_flags, &msg_flags))
return -EFAULT;

View file

@ -458,6 +458,7 @@ struct pollfd {
#define SHUT_RDWR 3
#define MSG_TRUNC 0x1
#define MSG_CTRUNC 0x2
#define MSG_DONTWAIT 0x40
#define SOL_SOCKET 1
@ -471,6 +472,11 @@ enum {
SO_REUSEADDR,
SO_BINDTODEVICE,
SO_KEEPALIVE,
SO_TIMESTAMP,
};
enum {
SCM_TIMESTAMP,
};
#define IPPROTO_IP 0
@ -556,6 +562,12 @@ struct iovec {
size_t iov_len;
};
struct cmsghdr {
socklen_t cmsg_len;
int cmsg_level;
int cmsg_type;
};
struct msghdr {
void* msg_name;
socklen_t msg_namelen;