stream.c 5.18 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
5
6
7
8
9
10
11
/*
 *     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)
12
 *                     Alan Cox <alan@lxorguk.ukuu.org.uk> (Borrowed comments 8-))
Linus Torvalds's avatar
Linus Torvalds committed
13
14
15
16
17
18
19
20
21
22
23
 */

#include <linux/module.h>
#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.
24
 * @sk: socket
Linus Torvalds's avatar
Linus Torvalds committed
25
26
27
28
29
30
 *
 * FIXME: write proper description
 */
void sk_stream_write_space(struct sock *sk)
{
	struct socket *sock = sk->sk_socket;
31
	struct socket_wq *wq;
Linus Torvalds's avatar
Linus Torvalds committed
32

33
	if (sk_stream_is_writeable(sk) && sock) {
Linus Torvalds's avatar
Linus Torvalds committed
34
35
		clear_bit(SOCK_NOSPACE, &sock->flags);

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

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

60
	do {
61
62
63
		int err = sock_error(sk);
		if (err)
			return err;
Linus Torvalds's avatar
Linus Torvalds committed
64
65
66
67
68
69
70
		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);

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

/**
 * sk_stream_closing - Return 1 if we still have things to send in our buffers.
86
 * @sk: socket to verify
Linus Torvalds's avatar
Linus Torvalds committed
87
88
89
90
91
92
93
94
95
96
 */
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) {
97
98
99
		DEFINE_WAIT_FUNC(wait, woken_wake_function);

		add_wait_queue(sk_sleep(sk), &wait);
Linus Torvalds's avatar
Linus Torvalds committed
100
101

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

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

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

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

127
128
	add_wait_queue(sk_sleep(sk), &wait);

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

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

		set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
		sk->sk_write_pending++;
147
148
149
		sk_wait_event(sk, &current_timeo, sk->sk_err ||
						  (sk->sk_shutdown & SEND_SHUTDOWN) ||
						  (sk_stream_memory_free(sk) &&
150
						  !vm_wait), &wait);
Linus Torvalds's avatar
Linus Torvalds committed
151
152
153
154
155
156
157
158
159
160
161
162
163
		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:
164
	remove_wait_queue(sk_sleep(sk), &wait);
Linus Torvalds's avatar
Linus Torvalds committed
165
166
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
	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. */
198
	WARN_ON(!skb_queue_empty(&sk->sk_write_queue));
Linus Torvalds's avatar
Linus Torvalds committed
199
200

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

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

	/* 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);