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
so_notify_connected(struct sonode * so)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
so_notify_disconnecting(struct sonode * so)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
so_notify_disconnected(struct sonode * so,boolean_t connfailed,int error)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
so_notify_writable(struct sonode * so)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
so_notify_data(struct sonode * so,size_t qlen)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
so_notify_error(struct sonode * so)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
so_notify_oobsig(struct sonode * so)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
so_notify_oobdata(struct sonode * so,boolean_t oob_inline)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
so_notify_eof(struct sonode * so)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
so_notify_newconn(struct sonode * so)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
so_notify_shutdown(struct sonode * so)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
i_so_notify_last_rx(struct sonode * so,int * pollev,int * sigev)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
i_so_notify_last_tx(struct sonode * so,int * pollev,int * sigev)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