xref: /illumos-gate/usr/src/uts/common/fs/sockfs/socknotify.c (revision e0731422366620894c16c1ee6515551c5f00733d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/stropts.h>
30 #include <sys/socketvar.h>
31 #include <sys/ksocket.h>
32 #include <io/ksocket/ksocket_impl.h>
33 #include <fs/sockfs/sockcommon.h>
34 #include <fs/sockfs/sodirect.h>
35 #include <fs/sockfs/sockfilter_impl.h>
36 
37 /*
38  * There can only be a single thread waiting for data (enforced by
39  * so_lock_read()), whereas for write there might be multiple threads
40  * waiting for transmit buffers. So therefore we use cv_broadcast for
41  * write and cv_signal for read.
42  */
43 #define	SO_WAKEUP_READER(so) {				\
44 	if ((so)->so_rcv_wakeup) {			\
45 		(so)->so_rcv_wakeup = B_FALSE;		\
46 		cv_signal(&(so)->so_rcv_cv);		\
47 	}						\
48 }
49 
50 #define	SO_WAKEUP_WRITER(so) {			\
51 	if ((so)->so_snd_wakeup) {		\
52 		(so)->so_snd_wakeup = B_FALSE;	\
53 		cv_broadcast(&(so)->so_snd_cv);	\
54 	}					\
55 }
56 
57 static int i_so_notify_last_rx(struct sonode *, int *, int *);
58 static int i_so_notify_last_tx(struct sonode *, int *, int *);
59 
60 /*
61  * The notification functions must be called with so_lock held,
62  * and they will all *drop* so_lock before returning.
63  */
64 
65 /*
66  * Wake up anyone waiting for the connection to be established.
67  */
68 void
69 so_notify_connected(struct sonode *so)
70 {
71 	ASSERT(MUTEX_HELD(&so->so_lock));
72 
73 	if (IS_KERNEL_SOCKET(so)) {
74 		KSOCKET_CALLBACK(so, connected, 0);
75 		mutex_exit(&so->so_lock);
76 	} else {
77 		socket_sendsig(so, SOCKETSIG_WRITE);
78 		mutex_exit(&so->so_lock);
79 		pollwakeup(&so->so_poll_list, POLLOUT);
80 	}
81 	sof_sonode_notify_filters(so, SOF_EV_CONNECTED, 0);
82 
83 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
84 }
85 
86 /*
87  * The socket is disconnecting, so no more data can be sent. Wake up
88  * anyone that is waiting to send data.
89  */
90 void
91 so_notify_disconnecting(struct sonode *so)
92 {
93 	int pollev = 0;
94 	int sigev = 0;
95 
96 	ASSERT(MUTEX_HELD(&so->so_lock));
97 	(void) i_so_notify_last_tx(so, &pollev, &sigev);
98 
99 	if (IS_KERNEL_SOCKET(so)) {
100 		KSOCKET_CALLBACK(so, cantsendmore, 0);
101 		mutex_exit(&so->so_lock);
102 	} else {
103 		if (sigev != 0)
104 			socket_sendsig(so, sigev);
105 		mutex_exit(&so->so_lock);
106 		if (pollev != 0)
107 			pollwakeup(&so->so_poll_list, pollev);
108 	}
109 	sof_sonode_notify_filters(so, SOF_EV_CANTSENDMORE, 0);
110 
111 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
112 }
113 
114 /*
115  * The socket is disconnected, so not more data can be sent or received.
116  * Wake up anyone that is waiting to send or receive data.
117  */
118 void
119 so_notify_disconnected(struct sonode *so, boolean_t connfailed, int error)
120 {
121 	int pollev = 0;
122 	int sigev = 0;
123 
124 	ASSERT(MUTEX_HELD(&so->so_lock));
125 
126 	(void) i_so_notify_last_tx(so, &pollev, &sigev);
127 	(void) i_so_notify_last_rx(so, &pollev, &sigev);
128 
129 	if (IS_KERNEL_SOCKET(so)) {
130 		if (connfailed) {
131 			KSOCKET_CALLBACK(so, disconnected, error);
132 		} else {
133 			KSOCKET_CALLBACK(so, connectfailed, error);
134 		}
135 		mutex_exit(&so->so_lock);
136 	} else {
137 		if (sigev != 0)
138 			socket_sendsig(so, sigev);
139 		mutex_exit(&so->so_lock);
140 		if (pollev != 0)
141 			pollwakeup(&so->so_poll_list, pollev);
142 	}
143 	sof_sonode_notify_filters(so, (connfailed) ? SOF_EV_CONNECTFAILED :
144 	    SOF_EV_DISCONNECTED, error);
145 
146 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
147 }
148 
149 /*
150  * The socket is writeable. Wake up anyone waiting to send data.
151  */
152 void
153 so_notify_writable(struct sonode *so)
154 {
155 	ASSERT(MUTEX_HELD(&so->so_lock));
156 
157 	SO_WAKEUP_WRITER(so);
158 
159 	if (IS_KERNEL_SOCKET(so)) {
160 		KSOCKET_CALLBACK(so, cansend, 0);
161 		mutex_exit(&so->so_lock);
162 	} else {
163 		socket_sendsig(so, SOCKETSIG_WRITE);
164 		mutex_exit(&so->so_lock);
165 		pollwakeup(&so->so_poll_list, POLLOUT);
166 	}
167 
168 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
169 
170 	/* filters can start injecting data */
171 	if (so->so_filter_active > 0)
172 		sof_sonode_notify_filters(so, SOF_EV_INJECT_DATA_OUT_OK, 0);
173 }
174 
175 /*
176  * Data is available, so wake up anyone waiting for data.
177  */
178 void
179 so_notify_data(struct sonode *so, size_t qlen)
180 {
181 	ASSERT(MUTEX_HELD(&so->so_lock));
182 
183 	SO_WAKEUP_READER(so);
184 
185 	if (IS_KERNEL_SOCKET(so)) {
186 		KSOCKET_CALLBACK(so, newdata, qlen);
187 		mutex_exit(&so->so_lock);
188 	} else {
189 		socket_sendsig(so, SOCKETSIG_READ);
190 		if (so->so_pollev & (SO_POLLEV_IN|SO_POLLEV_ALWAYS)) {
191 			so->so_pollev &= ~SO_POLLEV_IN;
192 			mutex_exit(&so->so_lock);
193 			pollwakeup(&so->so_poll_list, POLLIN|POLLRDNORM);
194 		} else {
195 			mutex_exit(&so->so_lock);
196 		}
197 	}
198 
199 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
200 }
201 
202 /*
203  * Transient error. Wake up anyone waiting to send or receive data.
204  */
205 void
206 so_notify_error(struct sonode *so)
207 {
208 	ASSERT(MUTEX_HELD(&so->so_lock));
209 
210 	SO_WAKEUP_WRITER(so);
211 	SO_WAKEUP_READER(so);
212 
213 	if (IS_KERNEL_SOCKET(so)) {
214 		KSOCKET_CALLBACK(so, error, 0);
215 		mutex_exit(&so->so_lock);
216 	} else {
217 		socket_sendsig(so, SOCKETSIG_WRITE|SOCKETSIG_READ);
218 		so->so_pollev &= ~SO_POLLEV_IN;
219 		mutex_exit(&so->so_lock);
220 		pollwakeup(&so->so_poll_list, POLLOUT|POLLIN|POLLRDNORM);
221 	}
222 
223 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
224 }
225 
226 /*
227  * Out-of-band data is incoming, notify any interested parties.
228  */
229 void
230 so_notify_oobsig(struct sonode *so)
231 {
232 	socket_sendsig(so, SOCKETSIG_URG);
233 	mutex_exit(&so->so_lock);
234 	pollwakeup(&so->so_poll_list, POLLRDBAND);
235 }
236 
237 /*
238  * Received out-of-band data. If the OOB data is delivered inline, then
239  * in addition of regular OOB notification, anyone waiting for normal
240  * data is also notified.
241  */
242 void
243 so_notify_oobdata(struct sonode *so, boolean_t oob_inline)
244 {
245 	ASSERT(MUTEX_HELD(&so->so_lock));
246 	if (so->so_direct != NULL)
247 		SOD_UIOAFINI(so->so_direct);
248 
249 	SO_WAKEUP_READER(so);
250 
251 	if (IS_KERNEL_SOCKET(so)) {
252 		KSOCKET_CALLBACK(so, oobdata, 0);
253 		mutex_exit(&so->so_lock);
254 	} else {
255 		if (oob_inline) {
256 			socket_sendsig(so, SOCKETSIG_READ);
257 			so->so_pollev &= ~SO_POLLEV_IN;
258 			mutex_exit(&so->so_lock);
259 			pollwakeup(&so->so_poll_list,
260 			    POLLRDBAND|POLLIN|POLLRDNORM);
261 		} else {
262 			mutex_exit(&so->so_lock);
263 			pollwakeup(&so->so_poll_list, POLLRDBAND);
264 		}
265 	}
266 
267 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
268 }
269 
270 /*
271  * End-of-file has been reach, so peer will send no new data. Wake up
272  * anyone that is waiting for data.
273  */
274 void
275 so_notify_eof(struct sonode *so)
276 {
277 	int pollev = 0;
278 	int sigev = 0;
279 
280 	ASSERT(MUTEX_HELD(&so->so_lock));
281 
282 	(void) i_so_notify_last_rx(so, &pollev, &sigev);
283 
284 	if (IS_KERNEL_SOCKET(so)) {
285 		KSOCKET_CALLBACK(so, cantrecvmore, 0);
286 		mutex_exit(&so->so_lock);
287 	} else {
288 		if (sigev != 0)
289 			socket_sendsig(so, sigev);
290 		mutex_exit(&so->so_lock);
291 		if (pollev != 0)
292 			pollwakeup(&so->so_poll_list, pollev);
293 
294 	}
295 	sof_sonode_notify_filters(so, SOF_EV_CANTRECVMORE, 0);
296 
297 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
298 }
299 
300 /*
301  * Wake up anyone waiting for a new connection.
302  */
303 void
304 so_notify_newconn(struct sonode *so)
305 {
306 	ASSERT(MUTEX_HELD(&so->so_lock));
307 
308 	if (IS_KERNEL_SOCKET(so)) {
309 		KSOCKET_CALLBACK(so, newconn, 0);
310 		mutex_exit(&so->so_lock);
311 	} else {
312 		socket_sendsig(so, SOCKETSIG_READ);
313 		if (so->so_pollev & (SO_POLLEV_IN|SO_POLLEV_ALWAYS)) {
314 			so->so_pollev &= ~SO_POLLEV_IN;
315 			mutex_exit(&so->so_lock);
316 			pollwakeup(&so->so_poll_list, POLLIN|POLLRDNORM);
317 		} else {
318 			mutex_exit(&so->so_lock);
319 		}
320 	}
321 
322 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
323 }
324 
325 /*
326  * User initated shutdown/close, wake anyone that is trying to do
327  * an operation that is no longer possible.
328  */
329 void
330 so_notify_shutdown(struct sonode *so)
331 {
332 	int pollev = 0;
333 	int sigev = 0;
334 
335 	ASSERT(MUTEX_HELD(&so->so_lock));
336 	ASSERT(so->so_state & (SS_CANTSENDMORE|SS_CANTRCVMORE));
337 
338 	if (so->so_state & SS_CANTSENDMORE)
339 		(void) i_so_notify_last_tx(so, &pollev, &sigev);
340 	if (so->so_state & SS_CANTRCVMORE)
341 		(void) i_so_notify_last_rx(so, &pollev, &sigev);
342 
343 	if (sigev != 0)
344 		socket_sendsig(so, sigev);
345 	mutex_exit(&so->so_lock);
346 	if (pollev != 0)
347 		pollwakeup(&so->so_poll_list, pollev);
348 
349 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
350 }
351 
352 /*
353  * No more data will be coming in, and this will be the last notification
354  * made.
355  */
356 static int
357 i_so_notify_last_rx(struct sonode *so, int *pollev, int *sigev)
358 {
359 	if (!(so->so_state & SS_SENTLASTREADSIG)) {
360 		SOCKET_TIMER_CANCEL(so);
361 		SO_WAKEUP_READER(so);
362 		so->so_state |= SS_SENTLASTREADSIG;
363 		so->so_pollev &= ~SO_POLLEV_IN;
364 
365 		*pollev |= POLLIN|POLLRDNORM;
366 		*sigev |= SOCKETSIG_READ;
367 
368 		return (1);
369 	} else {
370 		return (0);
371 	}
372 }
373 
374 /*
375  * The socket is un-writeable. Make one last notification.
376  */
377 static int
378 i_so_notify_last_tx(struct sonode *so, int *pollev, int *sigev)
379 {
380 	if (!(so->so_state & SS_SENTLASTWRITESIG)) {
381 		SO_WAKEUP_WRITER(so);
382 		so->so_state |= SS_SENTLASTWRITESIG;
383 
384 		*pollev |= POLLOUT;
385 		*sigev |= SOCKETSIG_WRITE;
386 
387 		return (1);
388 	} else {
389 		return (0);
390 	}
391 }
392