sock: Introduce the SO_PEEK_OFF sock option
This one specifies where to start MSG_PEEK-ing queue data from. When set to negative value means that MSG_PEEK works as ususally -- peeks from the head of the queue always. When some bytes are peeked from queue and the peeking offset is non negative it is moved forward so that the next peek will return next portion of data. When non-peeking recvmsg occurs and the peeking offset is non negative is is moved backward so that the next peek will still peek the proper data (i.e. the one that would have been picked if there were no non peeking recv in between). The offset is set using per-proto opteration to let the protocol handle the locking issues and to check whether the peeking offset feature is supported by the protocol the socket belongs to. Signed-off-by: Pavel Emelyanov <xemul@parallels.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
da5ef6e51b
commit
ef64a54f6e
|
@ -71,6 +71,7 @@
|
||||||
|
|
||||||
#define SO_WIFI_STATUS 41
|
#define SO_WIFI_STATUS 41
|
||||||
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
||||||
|
#define SO_PEEK_OFF 42
|
||||||
|
|
||||||
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we
|
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we
|
||||||
* have to define SOCK_NONBLOCK to a different value here.
|
* have to define SOCK_NONBLOCK to a different value here.
|
||||||
|
|
|
@ -64,5 +64,6 @@
|
||||||
|
|
||||||
#define SO_WIFI_STATUS 41
|
#define SO_WIFI_STATUS 41
|
||||||
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
||||||
|
#define SO_PEEK_OFF 42
|
||||||
|
|
||||||
#endif /* _ASM_SOCKET_H */
|
#endif /* _ASM_SOCKET_H */
|
||||||
|
|
|
@ -64,5 +64,6 @@
|
||||||
|
|
||||||
#define SO_WIFI_STATUS 41
|
#define SO_WIFI_STATUS 41
|
||||||
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
||||||
|
#define SO_PEEK_OFF 42
|
||||||
|
|
||||||
#endif /* __ASM_AVR32_SOCKET_H */
|
#endif /* __ASM_AVR32_SOCKET_H */
|
||||||
|
|
|
@ -66,6 +66,7 @@
|
||||||
|
|
||||||
#define SO_WIFI_STATUS 41
|
#define SO_WIFI_STATUS 41
|
||||||
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
||||||
|
#define SO_PEEK_OFF 42
|
||||||
|
|
||||||
#endif /* _ASM_SOCKET_H */
|
#endif /* _ASM_SOCKET_H */
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,7 @@
|
||||||
|
|
||||||
#define SO_WIFI_STATUS 41
|
#define SO_WIFI_STATUS 41
|
||||||
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
||||||
|
#define SO_PEEK_OFF 42
|
||||||
|
|
||||||
#endif /* _ASM_SOCKET_H */
|
#endif /* _ASM_SOCKET_H */
|
||||||
|
|
||||||
|
|
|
@ -64,5 +64,6 @@
|
||||||
|
|
||||||
#define SO_WIFI_STATUS 41
|
#define SO_WIFI_STATUS 41
|
||||||
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
||||||
|
#define SO_PEEK_OFF 42
|
||||||
|
|
||||||
#endif /* _ASM_SOCKET_H */
|
#endif /* _ASM_SOCKET_H */
|
||||||
|
|
|
@ -73,5 +73,6 @@
|
||||||
|
|
||||||
#define SO_WIFI_STATUS 41
|
#define SO_WIFI_STATUS 41
|
||||||
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
||||||
|
#define SO_PEEK_OFF 42
|
||||||
|
|
||||||
#endif /* _ASM_IA64_SOCKET_H */
|
#endif /* _ASM_IA64_SOCKET_H */
|
||||||
|
|
|
@ -64,5 +64,6 @@
|
||||||
|
|
||||||
#define SO_WIFI_STATUS 41
|
#define SO_WIFI_STATUS 41
|
||||||
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
||||||
|
#define SO_PEEK_OFF 42
|
||||||
|
|
||||||
#endif /* _ASM_M32R_SOCKET_H */
|
#endif /* _ASM_M32R_SOCKET_H */
|
||||||
|
|
|
@ -64,5 +64,6 @@
|
||||||
|
|
||||||
#define SO_WIFI_STATUS 41
|
#define SO_WIFI_STATUS 41
|
||||||
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
||||||
|
#define SO_PEEK_OFF 42
|
||||||
|
|
||||||
#endif /* _ASM_SOCKET_H */
|
#endif /* _ASM_SOCKET_H */
|
||||||
|
|
|
@ -84,6 +84,7 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */
|
||||||
|
|
||||||
#define SO_WIFI_STATUS 41
|
#define SO_WIFI_STATUS 41
|
||||||
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
||||||
|
#define SO_PEEK_OFF 42
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
|
|
|
@ -64,5 +64,6 @@
|
||||||
|
|
||||||
#define SO_WIFI_STATUS 41
|
#define SO_WIFI_STATUS 41
|
||||||
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
||||||
|
#define SO_PEEK_OFF 42
|
||||||
|
|
||||||
#endif /* _ASM_SOCKET_H */
|
#endif /* _ASM_SOCKET_H */
|
||||||
|
|
|
@ -63,6 +63,7 @@
|
||||||
|
|
||||||
#define SO_WIFI_STATUS 0x4022
|
#define SO_WIFI_STATUS 0x4022
|
||||||
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
||||||
|
#define SO_PEEK_OFF 0x4023
|
||||||
|
|
||||||
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we
|
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we
|
||||||
* have to define SOCK_NONBLOCK to a different value here.
|
* have to define SOCK_NONBLOCK to a different value here.
|
||||||
|
|
|
@ -71,5 +71,6 @@
|
||||||
|
|
||||||
#define SO_WIFI_STATUS 41
|
#define SO_WIFI_STATUS 41
|
||||||
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
||||||
|
#define SO_PEEK_OFF 42
|
||||||
|
|
||||||
#endif /* _ASM_POWERPC_SOCKET_H */
|
#endif /* _ASM_POWERPC_SOCKET_H */
|
||||||
|
|
|
@ -72,5 +72,6 @@
|
||||||
|
|
||||||
#define SO_WIFI_STATUS 41
|
#define SO_WIFI_STATUS 41
|
||||||
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
||||||
|
#define SO_PEEK_OFF 42
|
||||||
|
|
||||||
#endif /* _ASM_SOCKET_H */
|
#endif /* _ASM_SOCKET_H */
|
||||||
|
|
|
@ -60,6 +60,7 @@
|
||||||
|
|
||||||
#define SO_WIFI_STATUS 0x0025
|
#define SO_WIFI_STATUS 0x0025
|
||||||
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
||||||
|
#define SO_PEEK_OFF 0x0026
|
||||||
|
|
||||||
/* Security levels - as per NRL IPv6 - don't actually do anything */
|
/* Security levels - as per NRL IPv6 - don't actually do anything */
|
||||||
#define SO_SECURITY_AUTHENTICATION 0x5001
|
#define SO_SECURITY_AUTHENTICATION 0x5001
|
||||||
|
|
|
@ -75,5 +75,6 @@
|
||||||
|
|
||||||
#define SO_WIFI_STATUS 41
|
#define SO_WIFI_STATUS 41
|
||||||
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
||||||
|
#define SO_PEEK_OFF 42
|
||||||
|
|
||||||
#endif /* _XTENSA_SOCKET_H */
|
#endif /* _XTENSA_SOCKET_H */
|
||||||
|
|
|
@ -67,4 +67,5 @@
|
||||||
|
|
||||||
#define SO_WIFI_STATUS 41
|
#define SO_WIFI_STATUS 41
|
||||||
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
#define SCM_WIFI_STATUS SO_WIFI_STATUS
|
||||||
|
#define SO_PEEK_OFF 42
|
||||||
#endif /* __ASM_GENERIC_SOCKET_H */
|
#endif /* __ASM_GENERIC_SOCKET_H */
|
||||||
|
|
|
@ -206,6 +206,7 @@ struct proto_ops {
|
||||||
int offset, size_t size, int flags);
|
int offset, size_t size, int flags);
|
||||||
ssize_t (*splice_read)(struct socket *sock, loff_t *ppos,
|
ssize_t (*splice_read)(struct socket *sock, loff_t *ppos,
|
||||||
struct pipe_inode_info *pipe, size_t len, unsigned int flags);
|
struct pipe_inode_info *pipe, size_t len, unsigned int flags);
|
||||||
|
void (*set_peek_off)(struct sock *sk, int val);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DECLARE_SOCKADDR(type, dst, src) \
|
#define DECLARE_SOCKADDR(type, dst, src) \
|
||||||
|
|
|
@ -357,6 +357,7 @@ struct sock {
|
||||||
struct page *sk_sndmsg_page;
|
struct page *sk_sndmsg_page;
|
||||||
struct sk_buff *sk_send_head;
|
struct sk_buff *sk_send_head;
|
||||||
__u32 sk_sndmsg_off;
|
__u32 sk_sndmsg_off;
|
||||||
|
__s32 sk_peek_off;
|
||||||
int sk_write_pending;
|
int sk_write_pending;
|
||||||
#ifdef CONFIG_SECURITY
|
#ifdef CONFIG_SECURITY
|
||||||
void *sk_security;
|
void *sk_security;
|
||||||
|
@ -373,6 +374,30 @@ struct sock {
|
||||||
void (*sk_destruct)(struct sock *sk);
|
void (*sk_destruct)(struct sock *sk);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline int sk_peek_offset(struct sock *sk, int flags)
|
||||||
|
{
|
||||||
|
if ((flags & MSG_PEEK) && (sk->sk_peek_off >= 0))
|
||||||
|
return sk->sk_peek_off;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sk_peek_offset_bwd(struct sock *sk, int val)
|
||||||
|
{
|
||||||
|
if (sk->sk_peek_off >= 0) {
|
||||||
|
if (sk->sk_peek_off >= val)
|
||||||
|
sk->sk_peek_off -= val;
|
||||||
|
else
|
||||||
|
sk->sk_peek_off = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sk_peek_offset_fwd(struct sock *sk, int val)
|
||||||
|
{
|
||||||
|
if (sk->sk_peek_off >= 0)
|
||||||
|
sk->sk_peek_off += val;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hashed lists helper routines
|
* Hashed lists helper routines
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -793,6 +793,12 @@ set_rcvbuf:
|
||||||
sock_valbool_flag(sk, SOCK_WIFI_STATUS, valbool);
|
sock_valbool_flag(sk, SOCK_WIFI_STATUS, valbool);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SO_PEEK_OFF:
|
||||||
|
if (sock->ops->set_peek_off)
|
||||||
|
sock->ops->set_peek_off(sk, val);
|
||||||
|
else
|
||||||
|
ret = -EOPNOTSUPP;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -ENOPROTOOPT;
|
ret = -ENOPROTOOPT;
|
||||||
break;
|
break;
|
||||||
|
@ -1018,6 +1024,12 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
|
||||||
v.val = !!sock_flag(sk, SOCK_WIFI_STATUS);
|
v.val = !!sock_flag(sk, SOCK_WIFI_STATUS);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SO_PEEK_OFF:
|
||||||
|
if (!sock->ops->set_peek_off)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
v.val = sk->sk_peek_off;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -ENOPROTOOPT;
|
return -ENOPROTOOPT;
|
||||||
}
|
}
|
||||||
|
@ -2092,6 +2104,7 @@ void sock_init_data(struct socket *sock, struct sock *sk)
|
||||||
|
|
||||||
sk->sk_sndmsg_page = NULL;
|
sk->sk_sndmsg_page = NULL;
|
||||||
sk->sk_sndmsg_off = 0;
|
sk->sk_sndmsg_off = 0;
|
||||||
|
sk->sk_peek_off = -1;
|
||||||
|
|
||||||
sk->sk_peer_pid = NULL;
|
sk->sk_peer_pid = NULL;
|
||||||
sk->sk_peer_cred = NULL;
|
sk->sk_peer_cred = NULL;
|
||||||
|
|
Loading…
Reference in a new issue