mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-04 05:20:30 +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:
parent
ae5ba4074d
commit
47b3e98af8
Notes:
sideshowbarker
2024-07-19 02:21:45 +09:00
Author: https://github.com/nico Commit: https://github.com/SerenityOS/serenity/commit/47b3e98af8b Pull-request: https://github.com/SerenityOS/serenity/pull/3510 Reviewed-by: https://github.com/bugaevc
6 changed files with 94 additions and 2 deletions
|
@ -490,10 +490,10 @@ int Emulator::virt$setsockopt(FlatPtr params_addr)
|
|||
Syscall::SC_setsockopt_params params;
|
||||
mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
|
||||
|
||||
if (params.option == SO_RCVTIMEO) {
|
||||
if (params.option == SO_RCVTIMEO || params.option == SO_TIMESTAMP) {
|
||||
auto host_value_buffer = ByteBuffer::create_zeroed(params.value_size);
|
||||
mmu().copy_from_vm(host_value_buffer.data(), (FlatPtr)params.value, params.value_size);
|
||||
int rc = setsockopt(params.sockfd, params.level, SO_RCVTIMEO, host_value_buffer.data(), host_value_buffer.size());
|
||||
int rc = setsockopt(params.sockfd, params.level, params.option, host_value_buffer.data(), host_value_buffer.size());
|
||||
if (rc < 0)
|
||||
return -errno;
|
||||
return rc;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -62,10 +62,17 @@ __BEGIN_DECLS
|
|||
#define IPPROTO_UDP 17
|
||||
|
||||
#define MSG_TRUNC 0x1
|
||||
#define MSG_CTRUNC 0x2
|
||||
#define MSG_DONTWAIT 0x40
|
||||
|
||||
typedef uint16_t sa_family_t;
|
||||
|
||||
struct cmsghdr {
|
||||
socklen_t cmsg_len;
|
||||
int cmsg_level;
|
||||
int cmsg_type;
|
||||
};
|
||||
|
||||
struct msghdr {
|
||||
void* msg_name;
|
||||
socklen_t msg_namelen;
|
||||
|
@ -99,6 +106,7 @@ enum {
|
|||
SO_REUSEADDR,
|
||||
SO_BINDTODEVICE,
|
||||
SO_KEEPALIVE,
|
||||
SO_TIMESTAMP,
|
||||
};
|
||||
#define SO_RCVTIMEO SO_RCVTIMEO
|
||||
#define SO_SNDTIMEO SO_SNDTIMEO
|
||||
|
@ -108,6 +116,12 @@ enum {
|
|||
#define SO_REUSEADDR SO_REUSEADDR
|
||||
#define SO_BINDTODEVICE SO_BINDTODEVICE
|
||||
#define SO_KEEPALIVE SO_KEEPALIVE
|
||||
#define SO_TIMESTAMP SO_TIMESTAMP
|
||||
|
||||
enum {
|
||||
SCM_TIMESTAMP,
|
||||
};
|
||||
#define SCM_TIMESTAMP SCM_TIMESTAMP
|
||||
|
||||
struct sockaddr_storage {
|
||||
union {
|
||||
|
@ -135,4 +149,30 @@ int getpeername(int sockfd, struct sockaddr*, socklen_t*);
|
|||
int sendfd(int sockfd, int fd);
|
||||
int recvfd(int sockfd);
|
||||
|
||||
// These three are non-POSIX, but common:
|
||||
#define CMSG_ALIGN(x) (((x) + sizeof(void*) - 1) & ~(sizeof(void*) - 1))
|
||||
#define CMSG_SPACE(x) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(x))
|
||||
#define CMSG_LEN(x) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (x))
|
||||
|
||||
static inline struct cmsghdr* CMSG_FIRSTHDR(struct msghdr* msg)
|
||||
{
|
||||
if (msg->msg_controllen < sizeof(struct cmsghdr))
|
||||
return 0;
|
||||
return (struct cmsghdr*)msg->msg_control;
|
||||
}
|
||||
|
||||
static inline struct cmsghdr* CMSG_NXTHDR(struct msghdr* msg, struct cmsghdr* cmsg)
|
||||
{
|
||||
struct cmsghdr* next = (struct cmsghdr*)((char*)cmsg + CMSG_ALIGN(cmsg->cmsg_len));
|
||||
unsigned offset = (char*)next - (char*)msg->msg_control;
|
||||
if (msg->msg_controllen < offset + sizeof(struct cmsghdr))
|
||||
return NULL;
|
||||
return next;
|
||||
}
|
||||
|
||||
static inline void* CMSG_DATA(struct cmsghdr* cmsg)
|
||||
{
|
||||
return (void*)(cmsg + 1);
|
||||
}
|
||||
|
||||
__END_DECLS
|
||||
|
|
Loading…
Reference in a new issue