]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/sys_socket.c
a215a42bcee0924722e4448ddd15a9a0da4897f7
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * Copyright (c) 1982, 1986, 1990, 1993
27 * The Regents of the University of California. All rights reserved.
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by the University of
40 * California, Berkeley and its contributors.
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * @(#)sys_socket.c 8.1 (Berkeley) 6/10/93
60 #include <sys/param.h>
61 #include <sys/systm.h>
63 #include <sys/protosw.h>
64 #include <sys/socket.h>
65 #include <sys/socketvar.h>
66 #include <sys/filio.h> /* XXX */
67 #include <sys/sockio.h>
70 #include <sys/filedesc.h>
73 #include <net/route.h>
75 int soo_read
__P((struct file
*fp
, struct uio
*uio
,
76 struct ucred
*cred
, int flags
, struct proc
*p
));
77 int soo_write
__P((struct file
*fp
, struct uio
*uio
,
78 struct ucred
*cred
, int flags
, struct proc
*p
));
79 int soo_close
__P((struct file
*fp
, struct proc
*p
));
81 int soo_select
__P((struct file
*fp
, int which
, void * wql
, struct proc
*p
));
83 struct fileops socketops
=
84 { soo_read
, soo_write
, soo_ioctl
, soo_select
, soo_close
};
88 soo_read(fp
, uio
, cred
, flags
, p
)
98 int (*fsoreceive
) __P((struct socket
*so
,
99 struct sockaddr
**paddr
,
100 struct uio
*uio
, struct mbuf
**mp0
,
101 struct mbuf
**controlp
, int *flagsp
));
104 thread_funnel_switch(KERNEL_FUNNEL
, NETWORK_FUNNEL
);
106 if ((so
= (struct socket
*)fp
->f_data
) == NULL
) {
107 /* This is not a valid open file descriptor */
108 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
112 fsoreceive
= so
->so_proto
->pr_usrreqs
->pru_soreceive
;
113 if (fsoreceive
!= soreceive
)
114 { kp
= sotokextcb(so
);
116 { if (kp
->e_soif
&& kp
->e_soif
->sf_soreceive
)
117 (*kp
->e_soif
->sf_soreceive
)(so
, 0, &uio
,
124 stat
= (*fsoreceive
)(so
, 0, uio
, 0, 0, 0);
125 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
131 soo_write(fp
, uio
, cred
, flags
, p
)
139 int (*fsosend
) __P((struct socket
*so
, struct sockaddr
*addr
,
140 struct uio
*uio
, struct mbuf
*top
,
141 struct mbuf
*control
, int flags
));
145 thread_funnel_switch(KERNEL_FUNNEL
, NETWORK_FUNNEL
);
147 if ((so
= (struct socket
*)fp
->f_data
) == NULL
) {
148 /* This is not a valid open file descriptor */
149 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
153 fsosend
= so
->so_proto
->pr_usrreqs
->pru_sosend
;
154 if (fsosend
!= sosend
)
155 { kp
= sotokextcb(so
);
157 { if (kp
->e_soif
&& kp
->e_soif
->sf_sosend
)
158 (*kp
->e_soif
->sf_sosend
)(so
, 0, &uio
,
164 stat
= (*fsosend
)(so
, 0, uio
, 0, 0, 0);
165 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
167 /* Generation of SIGPIPE can be controlled per socket */
168 if (stat
== EPIPE
&& uio
->uio_procp
&& !(so
->so_flags
& SOF_NOSIGPIPE
))
169 psignal(uio
->uio_procp
, SIGPIPE
);
175 soo_ioctl(fp
, cmd
, data
, p
)
178 register caddr_t data
;
181 register struct socket
*so
;
186 thread_funnel_switch(KERNEL_FUNNEL
, NETWORK_FUNNEL
);
188 if ((so
= (struct socket
*)fp
->f_data
) == NULL
) {
189 /* This is not a valid open file descriptor */
190 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
195 sopt
.sopt_level
= cmd
;
196 sopt
.sopt_name
= (int)data
;
200 { if (kp
->e_soif
&& kp
->e_soif
->sf_socontrol
)
201 (*kp
->e_soif
->sf_socontrol
)(so
, &sopt
, kp
);
209 so
->so_state
|= SS_NBIO
;
211 so
->so_state
&= ~SS_NBIO
;
213 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
218 so
->so_state
|= SS_ASYNC
;
219 so
->so_rcv
.sb_flags
|= SB_ASYNC
;
220 so
->so_snd
.sb_flags
|= SB_ASYNC
;
222 so
->so_state
&= ~SS_ASYNC
;
223 so
->so_rcv
.sb_flags
&= ~SB_ASYNC
;
224 so
->so_snd
.sb_flags
&= ~SB_ASYNC
;
226 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
230 *(int *)data
= so
->so_rcv
.sb_cc
;
231 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
235 so
->so_pgid
= *(int *)data
;
236 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
240 *(int *)data
= so
->so_pgid
;
241 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
245 *(int *)data
= (so
->so_state
&SS_RCVATMARK
) != 0;
246 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
251 * Set socket level options here and then call protocol
254 struct socket
*cloned_so
= NULL
;
255 int cloned_fd
= *(int *)data
;
257 /* let's make sure it's either -1 or a valid file descriptor */
258 if (cloned_fd
!= -1) {
259 struct file
*cloned_fp
;
260 error
= getsock(p
->p_fd
, cloned_fd
, &cloned_fp
);
262 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
266 cloned_so
= (struct socket
*)cloned_fp
->f_data
;
269 /* Always set socket non-blocking for OT */
270 fp
->f_flag
|= FNONBLOCK
;
271 so
->so_state
|= SS_NBIO
;
272 so
->so_options
|= SO_DONTTRUNC
| SO_WANTMORE
;
273 so
->so_flags
|= SOF_NOSIGPIPE
;
275 if (cloned_so
&& so
!= cloned_so
) {
277 so
->so_options
|= cloned_so
->so_options
& ~SO_ACCEPTCONN
;
280 if (so
->so_options
& SO_LINGER
)
281 so
->so_linger
= cloned_so
->so_linger
;
283 /* SO_SNDBUF, SO_RCVBUF */
284 if (cloned_so
->so_snd
.sb_hiwat
> 0) {
285 if (sbreserve(&so
->so_snd
, cloned_so
->so_snd
.sb_hiwat
) == 0) {
287 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
291 if (cloned_so
->so_rcv
.sb_hiwat
> 0) {
292 if (sbreserve(&so
->so_rcv
, cloned_so
->so_rcv
.sb_hiwat
) == 0) {
294 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
299 /* SO_SNDLOWAT, SO_RCVLOWAT */
300 so
->so_snd
.sb_lowat
=
301 (cloned_so
->so_snd
.sb_lowat
> so
->so_snd
.sb_hiwat
) ?
302 so
->so_snd
.sb_hiwat
: cloned_so
->so_snd
.sb_lowat
;
303 so
->so_rcv
.sb_lowat
=
304 (cloned_so
->so_rcv
.sb_lowat
> so
->so_rcv
.sb_hiwat
) ?
305 so
->so_rcv
.sb_hiwat
: cloned_so
->so_rcv
.sb_lowat
;
307 /* SO_SNDTIMEO, SO_RCVTIMEO */
308 so
->so_snd
.sb_timeo
= cloned_so
->so_snd
.sb_timeo
;
309 so
->so_rcv
.sb_timeo
= cloned_so
->so_rcv
.sb_timeo
;
312 error
= (*so
->so_proto
->pr_usrreqs
->pru_control
)(so
, cmd
, data
, 0, p
);
313 /* Just ignore protocols that do not understand it */
314 if (error
== EOPNOTSUPP
)
317 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
322 * Interface/routing/protocol specific ioctls:
323 * interface and routing ioctls should have a
324 * different entry since a socket's unnecessary
326 if (IOCGROUP(cmd
) == 'i')
327 error
= ifioctl(so
, cmd
, data
, p
);
329 if (IOCGROUP(cmd
) == 'r')
330 error
= rtioctl(cmd
, data
, p
);
332 error
= (*so
->so_proto
->pr_usrreqs
->pru_control
)(so
, cmd
, data
, 0, p
);
334 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
339 soo_select(fp
, which
, wql
, p
)
345 register struct socket
*so
= (struct socket
*)fp
->f_data
;
346 register int s
= splnet();
353 so
->so_rcv
.sb_flags
|= SB_SEL
;
354 if (soreadable(so
)) {
357 so
->so_rcv
.sb_flags
&= ~SB_SEL
;
360 selrecord(p
, &so
->so_rcv
.sb_sel
, wql
);
364 so
->so_snd
.sb_flags
|= SB_SEL
;
365 if (sowriteable(so
)) {
368 so
->so_snd
.sb_flags
&= ~SB_SEL
;
371 selrecord(p
, &so
->so_snd
.sb_sel
, wql
);
375 so
->so_rcv
.sb_flags
|= SB_SEL
;
376 if (so
->so_oobmark
|| (so
->so_state
& SS_RCVATMARK
)) {
379 so
->so_rcv
.sb_flags
&= ~SB_SEL
;
382 selrecord(p
, &so
->so_rcv
.sb_sel
, wql
);
393 register struct socket
*so
;
394 register struct stat
*ub
;
399 * DANGER: by the time we get the network funnel the socket
400 * may have been closed
402 thread_funnel_switch(KERNEL_FUNNEL
, NETWORK_FUNNEL
);
403 bzero((caddr_t
)ub
, sizeof (*ub
));
404 ub
->st_mode
= S_IFSOCK
;
405 stat
= (*so
->so_proto
->pr_usrreqs
->pru_sense
)(so
, ub
);
406 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
418 thread_funnel_switch(KERNEL_FUNNEL
, NETWORK_FUNNEL
);
421 error
= soclose((struct socket
*)fp
->f_data
);
423 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);