]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kpi_socket.c
2 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
24 #include <sys/kernel.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/socketvar.h>
28 #include <sys/param.h>
30 #include <sys/errno.h>
31 #include <sys/malloc.h>
32 #include <sys/protosw.h>
33 #include <sys/domain.h>
35 #include <sys/fcntl.h>
36 #include <sys/filio.h>
37 #include <sys/uio_internal.h>
38 #include <kern/lock.h>
40 extern void *memcpy(void *, const void *, size_t);
41 extern int soclose_locked(struct socket
*so
);
43 errno_t
sock_send_internal(
45 const struct msghdr
*msg
,
55 struct sockaddr
*from
,
63 struct socket
*new_so
;
64 lck_mtx_t
*mutex_held
;
68 if (sock
== NULL
|| new_sock
== NULL
) return EINVAL
;
70 if ((sock
->so_options
& SO_ACCEPTCONN
) == 0) {
71 socket_unlock(sock
, 1);
74 if ((flags
& ~(MSG_DONTWAIT
)) != 0) {
75 socket_unlock(sock
, 1);
78 if (((flags
& MSG_DONTWAIT
) != 0 || (sock
->so_state
& SS_NBIO
) != 0) &&
79 sock
->so_comp
.tqh_first
== NULL
) {
80 socket_unlock(sock
, 1);
84 if (sock
->so_proto
->pr_getlock
!= NULL
) {
85 mutex_held
= (*sock
->so_proto
->pr_getlock
)(sock
, 0);
89 mutex_held
= sock
->so_proto
->pr_domain
->dom_mtx
;
93 while (TAILQ_EMPTY(&sock
->so_comp
) && sock
->so_error
== 0) {
94 if (sock
->so_state
& SS_CANTRCVMORE
) {
95 sock
->so_error
= ECONNABORTED
;
98 error
= msleep((caddr_t
)&sock
->so_timeo
, mutex_held
, PSOCK
| PCATCH
, "sock_accept", 0);
100 socket_unlock(sock
, 1);
104 if (sock
->so_error
) {
105 error
= sock
->so_error
;
107 socket_unlock(sock
, 1);
111 new_so
= TAILQ_FIRST(&sock
->so_comp
);
112 TAILQ_REMOVE(&sock
->so_comp
, new_so
, so_list
);
114 socket_unlock(sock
, 1); /* release the head */
117 lck_mtx_assert(new_so
->so_proto
->pr_getlock(new_so
, 0),
118 LCK_MTX_ASSERT_NOTOWNED
);
119 socket_lock(new_so
, 1);
122 new_so
->so_state
&= ~SS_COMP
;
123 new_so
->so_head
= NULL
;
124 soacceptlock(new_so
, &sa
, 0);
127 new_so
->so_upcall
= callback
;
128 new_so
->so_upcallarg
= cookie
;
129 new_so
->so_rcv
.sb_flags
|= SB_UPCALL
;
134 if (fromlen
> sa
->sa_len
) fromlen
= sa
->sa_len
;
135 memcpy(from
, sa
, fromlen
);
137 if (sa
) FREE(sa
, M_SONAME
);
140 socket_unlock(new_so
, 1);
147 const struct sockaddr
*to
)
149 if (sock
== NULL
|| to
== NULL
) return EINVAL
;
151 return sobind(sock
, (struct sockaddr
*)to
);
157 const struct sockaddr
*to
,
161 lck_mtx_t
*mutex_held
;
163 if (sock
== NULL
|| to
== NULL
) return EINVAL
;
165 socket_lock(sock
, 1);
167 if ((sock
->so_state
& SS_ISCONNECTING
) &&
168 ((sock
->so_state
& SS_NBIO
) != 0 ||
169 (flags
& MSG_DONTWAIT
) != 0)) {
170 socket_unlock(sock
, 1);
173 error
= soconnectlock(sock
, (struct sockaddr
*)to
, 0);
175 if ((sock
->so_state
& SS_ISCONNECTING
) &&
176 ((sock
->so_state
& SS_NBIO
) != 0 || (flags
& MSG_DONTWAIT
) != 0)) {
177 socket_unlock(sock
, 1);
181 if (sock
->so_proto
->pr_getlock
!= NULL
)
182 mutex_held
= (*sock
->so_proto
->pr_getlock
)(sock
, 0);
184 mutex_held
= sock
->so_proto
->pr_domain
->dom_mtx
;
186 while ((sock
->so_state
& SS_ISCONNECTING
) && sock
->so_error
== 0) {
187 error
= msleep((caddr_t
)&sock
->so_timeo
, mutex_held
, PSOCK
| PCATCH
,
194 error
= sock
->so_error
;
199 sock
->so_state
&= ~SS_ISCONNECTING
;
201 socket_unlock(sock
, 1);
208 const struct timeval
*tv
)
210 lck_mtx_t
* mutex_held
;
214 socket_lock(sock
, 1);
216 // Check if we're already connected or if we've already errored out
217 if ((sock
->so_state
& SS_ISCONNECTING
) == 0 || sock
->so_error
) {
218 if (sock
->so_error
) {
219 retval
= sock
->so_error
;
223 if ((sock
->so_state
& SS_ISCONNECTED
) != 0)
231 // copied translation from timeval to hertz from SO_RCVTIMEO handling
232 if (tv
->tv_sec
< 0 || tv
->tv_sec
> SHRT_MAX
/ hz
||
233 tv
->tv_usec
< 0 || tv
->tv_usec
>= 1000000) {
238 ts
.tv_sec
= tv
->tv_sec
;
239 ts
.tv_nsec
= (tv
->tv_usec
* NSEC_PER_USEC
);
240 if ( (ts
.tv_sec
+ (ts
.tv_nsec
/NSEC_PER_SEC
))/100 > SHRT_MAX
) {
245 if (sock
->so_proto
->pr_getlock
!= NULL
)
246 mutex_held
= (*sock
->so_proto
->pr_getlock
)(sock
, 0);
248 mutex_held
= sock
->so_proto
->pr_domain
->dom_mtx
;
250 msleep((caddr_t
)&sock
->so_timeo
, mutex_held
, PSOCK
, "sock_connectwait", &ts
);
252 // Check if we're still waiting to connect
253 if ((sock
->so_state
& SS_ISCONNECTING
) && sock
->so_error
== 0) {
254 retval
= EINPROGRESS
;
258 if (sock
->so_error
) {
259 retval
= sock
->so_error
;
264 socket_unlock(sock
, 1);
273 socket_lock(sock
, 1);
276 sock
->so_rcv
.sb_flags
|= SB_NOINTR
; // This isn't safe
277 sock
->so_snd
.sb_flags
|= SB_NOINTR
; // This isn't safe
280 sock
->so_rcv
.sb_flags
&= ~SB_NOINTR
; // This isn't safe
281 sock
->so_snd
.sb_flags
&= ~SB_NOINTR
; // This isn't safe
284 socket_unlock(sock
, 1);
292 struct sockaddr
*peername
,
296 struct sockaddr
*sa
= NULL
;
298 if (sock
== NULL
|| peername
== NULL
|| peernamelen
< 0) return EINVAL
;
299 socket_lock(sock
, 1);
300 if ((sock
->so_state
& (SS_ISCONNECTED
|SS_ISCONFIRMING
)) == 0) {
301 socket_unlock(sock
, 1);
304 error
= sock
->so_proto
->pr_usrreqs
->pru_peeraddr(sock
, &sa
);
307 if (peernamelen
> sa
->sa_len
) peernamelen
= sa
->sa_len
;
308 memcpy(peername
, sa
, peernamelen
);
310 if (sa
) FREE(sa
, M_SONAME
);
311 socket_unlock(sock
, 1);
318 struct sockaddr
*sockname
,
322 struct sockaddr
*sa
= NULL
;
324 if (sock
== NULL
|| sockname
== NULL
|| socknamelen
< 0) return EINVAL
;
325 socket_lock(sock
, 1);
326 error
= sock
->so_proto
->pr_usrreqs
->pru_sockaddr(sock
, &sa
);
329 if (socknamelen
> sa
->sa_len
) socknamelen
= sa
->sa_len
;
330 memcpy(sockname
, sa
, socknamelen
);
332 if (sa
) FREE(sa
, M_SONAME
);
333 socket_unlock(sock
, 1);
348 if (sock
== NULL
|| optval
== NULL
|| optlen
== NULL
) return EINVAL
;
349 sopt
.sopt_dir
= SOPT_GET
;
350 sopt
.sopt_level
= level
;
351 sopt
.sopt_name
= optname
;
352 sopt
.sopt_val
= CAST_USER_ADDR_T(optval
);
353 sopt
.sopt_valsize
= *optlen
;
355 error
= sogetopt(sock
, &sopt
); /* will lock socket */
356 if (error
== 0) *optlen
= sopt
.sopt_valsize
;
363 unsigned long request
,
366 return soioctl(sock
, request
, argp
, NULL
); /* will lock socket */
379 if (sock
== NULL
|| optval
== NULL
) return EINVAL
;
380 sopt
.sopt_dir
= SOPT_SET
;
381 sopt
.sopt_level
= level
;
382 sopt
.sopt_name
= optname
;
383 sopt
.sopt_val
= CAST_USER_ADDR_T(optval
);
384 sopt
.sopt_valsize
= optlen
;
386 return sosetopt(sock
, &sopt
); /* will lock socket */
394 if (sock
== NULL
) return EINVAL
;
395 return solisten(sock
, backlog
); /* will lock socket */
399 sock_receive_internal(
407 struct mbuf
*control
= NULL
;
410 struct sockaddr
*fromsa
;
411 char uio_buf
[ UIO_SIZEOF((msg
!= NULL
) ? msg
->msg_iovlen
: 0) ];
413 if (sock
== NULL
) return EINVAL
;
415 auio
= uio_createwithbuffer(((msg
!= NULL
) ? msg
->msg_iovlen
: 0),
416 0, UIO_SYSSPACE
, UIO_READ
,
417 &uio_buf
[0], sizeof(uio_buf
));
418 if (msg
&& data
== NULL
) {
420 struct iovec_32
*tempp
= (struct iovec_32
*) msg
->msg_iov
;
422 for (i
= 0; i
< msg
->msg_iovlen
; i
++) {
423 uio_addiov(auio
, CAST_USER_ADDR_T((tempp
+ i
)->iov_base
), (tempp
+ i
)->iov_len
);
425 if (uio_resid(auio
) < 0) return EINVAL
;
428 uio_setresid(auio
, (uio_resid(auio
) + *recvdlen
));
430 length
= uio_resid(auio
);
435 if (msg
&& msg
->msg_control
) {
436 if ((size_t)msg
->msg_controllen
< sizeof(struct cmsghdr
)) return EINVAL
;
437 if ((size_t)msg
->msg_controllen
> MLEN
) return EINVAL
;
438 control
= m_get(M_NOWAIT
, MT_CONTROL
);
439 if (control
== NULL
) return ENOMEM
;
440 memcpy(mtod(control
, caddr_t
), msg
->msg_control
, msg
->msg_controllen
);
441 control
->m_len
= msg
->msg_controllen
;
444 /* let pru_soreceive handle the socket locking */
445 error
= sock
->so_proto
->pr_usrreqs
->pru_soreceive(sock
, &fromsa
, auio
,
446 data
, control
? &control
: NULL
, &flags
);
447 if (error
) goto cleanup
;
450 *recvdlen
= length
- uio_resid(auio
);
452 msg
->msg_flags
= flags
;
457 salen
= msg
->msg_namelen
;
458 if (msg
->msg_namelen
> 0 && fromsa
!= 0)
460 salen
= MIN(salen
, fromsa
->sa_len
);
461 memcpy(msg
->msg_name
, fromsa
,
462 msg
->msg_namelen
> fromsa
->sa_len
? fromsa
->sa_len
: msg
->msg_namelen
);
466 if (msg
->msg_control
)
468 struct mbuf
* m
= control
;
469 u_char
* ctlbuf
= msg
->msg_control
;
470 int clen
= msg
->msg_controllen
;
471 msg
->msg_controllen
= 0;
473 while (m
&& clen
> 0)
476 if (clen
>= m
->m_len
)
482 msg
->msg_flags
|= MSG_CTRUNC
;
485 memcpy(ctlbuf
, mtod(m
, caddr_t
), tocopy
);
490 msg
->msg_controllen
= (u_int32_t
)ctlbuf
- (u_int32_t
)msg
->msg_control
;
495 if (control
) m_freem(control
);
496 if (fromsa
) FREE(fromsa
, M_SONAME
);
508 (msg
->msg_iovlen
< 1) ||
509 (msg
->msg_iov
[0].iov_len
== 0) ||
510 (msg
->msg_iov
[0].iov_base
== NULL
))
512 return sock_receive_internal(sock
, msg
, NULL
, flags
, recvdlen
);
523 if (data
== NULL
|| recvlen
== 0 || *recvlen
<= 0 || (msg
&&
524 (msg
->msg_iov
!= NULL
|| msg
->msg_iovlen
!= 0)))
526 return sock_receive_internal(sock
, msg
, data
, flags
, recvlen
);
532 const struct msghdr
*msg
,
538 struct mbuf
*control
= NULL
;
541 char uio_buf
[ UIO_SIZEOF((msg
!= NULL
? msg
->msg_iovlen
: 1)) ];
548 if (data
== 0 && msg
!= NULL
) {
549 struct iovec_32
*tempp
= (struct iovec_32
*) msg
->msg_iov
;
551 auio
= uio_createwithbuffer(msg
->msg_iovlen
, 0, UIO_SYSSPACE
, UIO_WRITE
,
552 &uio_buf
[0], sizeof(uio_buf
));
557 for (i
= 0; i
< msg
->msg_iovlen
; i
++) {
558 uio_addiov(auio
, CAST_USER_ADDR_T((tempp
+ i
)->iov_base
), (tempp
+ i
)->iov_len
);
561 if (uio_resid(auio
) < 0) {
572 datalen
= uio_resid(auio
);
574 datalen
= data
->m_pkthdr
.len
;
576 if (msg
&& msg
->msg_control
)
578 if ((size_t)msg
->msg_controllen
< sizeof(struct cmsghdr
)) return EINVAL
;
579 if ((size_t)msg
->msg_controllen
> MLEN
) return EINVAL
;
580 control
= m_get(M_NOWAIT
, MT_CONTROL
);
581 if (control
== NULL
) {
585 memcpy(mtod(control
, caddr_t
), msg
->msg_control
, msg
->msg_controllen
);
586 control
->m_len
= msg
->msg_controllen
;
589 error
= sock
->so_proto
->pr_usrreqs
->pru_sosend(sock
, msg
!= NULL
?
590 (struct sockaddr
*)msg
->msg_name
: NULL
, auio
, data
, control
, flags
);
593 * Residual data is possible in the case of IO vectors but not
594 * in the mbuf case since the latter is treated as atomic send.
595 * If pru_sosend() consumed a portion of the iovecs data and
596 * the error returned is transient, treat it as success; this
597 * is consistent with sendit() behavior.
599 if (auio
!= NULL
&& uio_resid(auio
) != datalen
&&
600 (error
== ERESTART
|| error
== EINTR
|| error
== EWOULDBLOCK
))
603 if (error
== 0 && sentlen
!= NULL
) {
605 *sentlen
= datalen
- uio_resid(auio
);
613 * In cases where we detect an error before returning, we need to
614 * free the mbuf chain if there is one. sosend (and pru_sosend) will
615 * free the mbuf chain if they encounter an error.
630 const struct msghdr
*msg
,
634 if (msg
== NULL
|| msg
->msg_iov
== NULL
|| msg
->msg_iovlen
< 1)
636 return sock_send_internal(sock
, msg
, NULL
, flags
, sentlen
);
642 const struct msghdr
*msg
,
647 if (data
== NULL
|| (msg
&&
648 (msg
->msg_iov
!= NULL
|| msg
->msg_iovlen
!= 0))) {
653 return sock_send_internal(sock
, msg
, data
, flags
, sentlen
);
661 if (sock
== NULL
) return EINVAL
;
662 return soshutdown(sock
, how
);
665 typedef void (*so_upcall
)(struct socket
*sock
, void* arg
, int waitf
);
672 sock_upcall callback
,
677 if (new_so
== NULL
) return EINVAL
;
678 /* socreate will create an initial so_count */
679 error
= socreate(domain
, new_so
, type
, protocol
);
680 if (error
== 0 && callback
)
682 (*new_so
)->so_rcv
.sb_flags
|= SB_UPCALL
;
683 (*new_so
)->so_upcall
= (so_upcall
)callback
;
684 (*new_so
)->so_upcallarg
= context
;
693 if (sock
== NULL
) return;
697 /* Do we want this to be APPLE_PRIVATE API?: YES (LD 12/23/04)*/
702 if (sock
== NULL
) return;
703 socket_lock(sock
, 1);
704 sock
->so_retaincnt
++;
705 sock
->so_usecount
++; /* add extra reference for holding the socket */
706 socket_unlock(sock
, 1);
709 /* Do we want this to be APPLE_PRIVATE API? */
714 if (sock
== NULL
) return;
715 socket_lock(sock
, 1);
716 sock
->so_retaincnt
--;
717 if (sock
->so_retaincnt
< 0)
718 panic("sock_release: negative retain count for sock=%x cnt=%x\n",
719 sock
, sock
->so_retaincnt
);
720 if ((sock
->so_retaincnt
== 0) && (sock
->so_usecount
== 2))
721 soclose_locked(sock
); /* close socket only if the FD is not holding it */
723 sock
->so_usecount
--; /* remove extra reference holding the socket */
724 socket_unlock(sock
, 1);
732 if (sock
== NULL
) return EINVAL
;
733 socket_lock(sock
, 1);
736 sock
->so_state
|= SS_PRIV
;
740 sock
->so_state
&= ~SS_PRIV
;
742 socket_unlock(sock
, 1);
751 socket_lock(sock
, 1);
752 retval
= (sock
->so_state
& SS_ISCONNECTED
) != 0;
753 socket_unlock(sock
, 1);
762 socket_lock(sock
, 1);
763 retval
= (sock
->so_state
& SS_NBIO
) != 0;
764 socket_unlock(sock
, 1);
775 socket_lock(sock
, 1);
777 *outDomain
= sock
->so_proto
->pr_domain
->dom_family
;
779 *outType
= sock
->so_type
;
781 *outProtocol
= sock
->so_proto
->pr_protocol
;
782 socket_unlock(sock
, 1);