stream.c 5.25 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
Linus Torvalds's avatar
Linus Torvalds committed
2
3
4
5
6
7
8
9
10
11
12
/*
 *     SUCS NET3:
 *
 *     Generic stream handling routines. These are generic for most
 *     protocols. Even IP. Tonight 8-).
 *     This is used because TCP, LLC (others too) layer all have mostly
 *     identical sendmsg() and recvmsg() code.
 *     So we (will) share it here.
 *
 *     Authors:        Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 *                     (from old tcp.c code)
13
 *                     Alan Cox <alan@lxorguk.ukuu.org.uk> (Borrowed comments 8-))
Linus Torvalds's avatar
Linus Torvalds committed
14
15
16
 */

#include <linux/module.h>
17
#include <linux/sched/signal.h>
Linus Torvalds's avatar
Linus Torvalds committed
18
19
20
21
22
23
24
25
#include <linux/net.h>
#include <linux/signal.h>
#include <linux/tcp.h>
#include <linux/wait.h>
#include <net/sock.h>

/**
 * sk_stream_write_space - stream socket write_space callback.
26
 * @sk: socket
Linus Torvalds's avatar
Linus Torvalds committed
27
28
29
30
31
32
 *
 * FIXME: write proper description
 */
void sk_stream_write_space(struct sock *sk)
{
	struct socket *sock = sk->sk_socket;
33
	struct socket_wq *wq;
Linus Torvalds's avatar
Linus Torvalds committed
34

35
	if (__sk_stream_is_writeable(sk, 1) && sock) {
Linus Torvalds's avatar
Linus Torvalds committed
36
37
		clear_bit(SOCK_NOSPACE, &sock->flags);

38
39
		rcu_read_lock();
		wq = rcu_dereference(sk->sk_wq);
40
		if (skwq_has_sleeper(wq))
41
42
			wake_up_interruptible_poll(&wq->wait, EPOLLOUT |
						EPOLLWRNORM | EPOLLWRBAND);
43
		if (wq && wq->fasync_list && !(sk->sk_shutdown & SEND_SHUTDOWN))
44
			sock_wake_async(wq, SOCK_WAKE_SPACE, POLL_OUT);
45
		rcu_read_unlock();
Linus Torvalds's avatar
Linus Torvalds committed
46
47
48
49
50
	}
}

/**
 * sk_stream_wait_connect - Wait for a socket to get into the connected state
51
52
 * @sk: sock to wait on
 * @timeo_p: for how long to wait
Linus Torvalds's avatar
Linus Torvalds committed
53
54
55
56
57
 *
 * Must be called with the socket locked.
 */
int sk_stream_wait_connect(struct sock *sk, long *timeo_p)
{
58
	DEFINE_WAIT_FUNC(wait, woken_wake_function);
Linus Torvalds's avatar
Linus Torvalds committed
59
	struct task_struct *tsk = current;
60
	int done;
Linus Torvalds's avatar
Linus Torvalds committed
61

62
	do {
63
64
65
		int err = sock_error(sk);
		if (err)
			return err;
Linus Torvalds's avatar
Linus Torvalds committed
66
67
68
69
70
71
72
		if ((1 << sk->sk_state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV))
			return -EPIPE;
		if (!*timeo_p)
			return -EAGAIN;
		if (signal_pending(tsk))
			return sock_intr_errno(*timeo_p);

73
		add_wait_queue(sk_sleep(sk), &wait);
Linus Torvalds's avatar
Linus Torvalds committed
74
		sk->sk_write_pending++;
75
		done = sk_wait_event(sk, timeo_p,
76
				     !sk->sk_err &&
77
				     !((1 << sk->sk_state) &
78
79
				       ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)), &wait);
		remove_wait_queue(sk_sleep(sk), &wait);
Linus Torvalds's avatar
Linus Torvalds committed
80
		sk->sk_write_pending--;
81
	} while (!done);
Linus Torvalds's avatar
Linus Torvalds committed
82
83
84
85
86
87
	return 0;
}
EXPORT_SYMBOL(sk_stream_wait_connect);

/**
 * sk_stream_closing - Return 1 if we still have things to send in our buffers.
88
 * @sk: socket to verify
Linus Torvalds's avatar
Linus Torvalds committed
89
90
91
92
93
94
95
96
97
98
 */
static inline int sk_stream_closing(struct sock *sk)
{
	return (1 << sk->sk_state) &
	       (TCPF_FIN_WAIT1 | TCPF_CLOSING | TCPF_LAST_ACK);
}

void sk_stream_wait_close(struct sock *sk, long timeout)
{
	if (timeout) {
99
100
101
		DEFINE_WAIT_FUNC(wait, woken_wake_function);

		add_wait_queue(sk_sleep(sk), &wait);
Linus Torvalds's avatar
Linus Torvalds committed
102
103

		do {
104
			if (sk_wait_event(sk, &timeout, !sk_stream_closing(sk), &wait))
Linus Torvalds's avatar
Linus Torvalds committed
105
106
107
				break;
		} while (!signal_pending(current) && timeout);

108
		remove_wait_queue(sk_sleep(sk), &wait);
Linus Torvalds's avatar
Linus Torvalds committed
109
110
111
112
113
114
	}
}
EXPORT_SYMBOL(sk_stream_wait_close);

/**
 * sk_stream_wait_memory - Wait for more memory for a socket
115
116
 * @sk: socket to wait for memory
 * @timeo_p: for how long
Linus Torvalds's avatar
Linus Torvalds committed
117
118
119
120
121
122
 */
int sk_stream_wait_memory(struct sock *sk, long *timeo_p)
{
	int err = 0;
	long vm_wait = 0;
	long current_timeo = *timeo_p;
123
	bool noblock = (*timeo_p ? false : true);
124
	DEFINE_WAIT_FUNC(wait, woken_wake_function);
Linus Torvalds's avatar
Linus Torvalds committed
125
126

	if (sk_stream_memory_free(sk))
127
		current_timeo = vm_wait = (prandom_u32() % (HZ / 5)) + 2;
Linus Torvalds's avatar
Linus Torvalds committed
128

129
130
	add_wait_queue(sk_sleep(sk), &wait);

Linus Torvalds's avatar
Linus Torvalds committed
131
	while (1) {
132
		sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
Linus Torvalds's avatar
Linus Torvalds committed
133
134
135

		if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
			goto do_error;
136
137
138
		if (!*timeo_p) {
			if (noblock)
				set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
Linus Torvalds's avatar
Linus Torvalds committed
139
			goto do_nonblock;
140
		}
Linus Torvalds's avatar
Linus Torvalds committed
141
142
		if (signal_pending(current))
			goto do_interrupted;
143
		sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
Linus Torvalds's avatar
Linus Torvalds committed
144
145
146
147
148
		if (sk_stream_memory_free(sk) && !vm_wait)
			break;

		set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
		sk->sk_write_pending++;
149
150
151
		sk_wait_event(sk, &current_timeo, sk->sk_err ||
						  (sk->sk_shutdown & SEND_SHUTDOWN) ||
						  (sk_stream_memory_free(sk) &&
152
						  !vm_wait), &wait);
Linus Torvalds's avatar
Linus Torvalds committed
153
154
155
156
157
158
159
160
161
162
163
164
165
		sk->sk_write_pending--;

		if (vm_wait) {
			vm_wait -= current_timeo;
			current_timeo = *timeo_p;
			if (current_timeo != MAX_SCHEDULE_TIMEOUT &&
			    (current_timeo -= vm_wait) < 0)
				current_timeo = 0;
			vm_wait = 0;
		}
		*timeo_p = current_timeo;
	}
out:
166
	remove_wait_queue(sk_sleep(sk), &wait);
Linus Torvalds's avatar
Linus Torvalds committed
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
	return err;

do_error:
	err = -EPIPE;
	goto out;
do_nonblock:
	err = -EAGAIN;
	goto out;
do_interrupted:
	err = sock_intr_errno(*timeo_p);
	goto out;
}
EXPORT_SYMBOL(sk_stream_wait_memory);

int sk_stream_error(struct sock *sk, int flags, int err)
{
	if (err == -EPIPE)
		err = sock_error(sk) ? : -EPIPE;
	if (err == -EPIPE && !(flags & MSG_NOSIGNAL))
		send_sig(SIGPIPE, current, 0);
	return err;
}
EXPORT_SYMBOL(sk_stream_error);

void sk_stream_kill_queues(struct sock *sk)
{
	/* First the read buffer. */
	__skb_queue_purge(&sk->sk_receive_queue);

	/* Next, the error queue. */
	__skb_queue_purge(&sk->sk_error_queue);

	/* Next, the write queue. */
200
	WARN_ON(!skb_queue_empty(&sk->sk_write_queue));
Linus Torvalds's avatar
Linus Torvalds committed
201
202

	/* Account for returned memory. */
203
	sk_mem_reclaim(sk);
Linus Torvalds's avatar
Linus Torvalds committed
204

205
206
	WARN_ON(sk->sk_wmem_queued);
	WARN_ON(sk->sk_forward_alloc);
Linus Torvalds's avatar
Linus Torvalds committed
207
208
209
210
211
212
213

	/* It is _impossible_ for the backlog to contain anything
	 * when we get here.  All user references to this socket
	 * have gone away, only the net layer knows can touch it.
	 */
}
EXPORT_SYMBOL(sk_stream_kill_queues);