]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kpi_socket.c
xnu-792.6.56.tar.gz
[apple/xnu.git] / bsd / kern / kpi_socket.c
CommitLineData
91447636
A
1/*
2 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
ff6e181a
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
91447636 12 *
ff6e181a
A
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
91447636
A
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
ff6e181a
A
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
91447636
A
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#define __KPI__
25#include <sys/kernel.h>
26#include <sys/types.h>
27#include <sys/socket.h>
28#include <sys/socketvar.h>
29#include <sys/param.h>
30#include <sys/proc.h>
31#include <sys/errno.h>
32#include <sys/malloc.h>
33#include <sys/protosw.h>
34#include <sys/domain.h>
35#include <sys/mbuf.h>
36#include <sys/fcntl.h>
37#include <sys/filio.h>
38#include <sys/uio_internal.h>
39#include <kern/lock.h>
40
41extern void *memcpy(void *, const void *, size_t);
42extern int soclose_locked(struct socket *so);
43
44errno_t sock_send_internal(
45 socket_t sock,
46 const struct msghdr *msg,
47 mbuf_t data,
48 int flags,
49 size_t *sentlen);
50
51
52
53errno_t
54sock_accept(
55 socket_t sock,
56 struct sockaddr *from,
57 int fromlen,
58 int flags,
59 sock_upcall callback,
60 void* cookie,
61 socket_t *new_sock)
62{
63 struct sockaddr *sa;
64 struct socket *new_so;
65 lck_mtx_t *mutex_held;
66 int dosocklock;
67 errno_t error = 0;
68
69 if (sock == NULL || new_sock == NULL) return EINVAL;
70 socket_lock(sock, 1);
71 if ((sock->so_options & SO_ACCEPTCONN) == 0) {
72 socket_unlock(sock, 1);
73 return EINVAL;
74 }
75 if ((flags & ~(MSG_DONTWAIT)) != 0) {
76 socket_unlock(sock, 1);
77 return ENOTSUP;
78 }
79 if (((flags & MSG_DONTWAIT) != 0 || (sock->so_state & SS_NBIO) != 0) &&
80 sock->so_comp.tqh_first == NULL) {
81 socket_unlock(sock, 1);
82 return EWOULDBLOCK;
83 }
84
85 if (sock->so_proto->pr_getlock != NULL) {
86 mutex_held = (*sock->so_proto->pr_getlock)(sock, 0);
87 dosocklock = 1;
88 }
89 else {
90 mutex_held = sock->so_proto->pr_domain->dom_mtx;
91 dosocklock = 0;
92 }
93
94 while (TAILQ_EMPTY(&sock->so_comp) && sock->so_error == 0) {
95 if (sock->so_state & SS_CANTRCVMORE) {
96 sock->so_error = ECONNABORTED;
97 break;
98 }
99 error = msleep((caddr_t)&sock->so_timeo, mutex_held, PSOCK | PCATCH, "sock_accept", 0);
100 if (error) {
101 socket_unlock(sock, 1);
102 return (error);
103 }
104 }
105 if (sock->so_error) {
106 error = sock->so_error;
107 sock->so_error = 0;
108 socket_unlock(sock, 1);
109 return (error);
110 }
111
112 new_so = TAILQ_FIRST(&sock->so_comp);
113 TAILQ_REMOVE(&sock->so_comp, new_so, so_list);
114 sock->so_qlen--;
115 socket_unlock(sock, 1); /* release the head */
116
117 if (dosocklock) {
118 lck_mtx_assert(new_so->so_proto->pr_getlock(new_so, 0),
119 LCK_MTX_ASSERT_NOTOWNED);
120 socket_lock(new_so, 1);
121 }
122
123 new_so->so_state &= ~SS_COMP;
124 new_so->so_head = NULL;
125 soacceptlock(new_so, &sa, 0);
126
127 if (callback) {
128 new_so->so_upcall = callback;
129 new_so->so_upcallarg = cookie;
130 new_so->so_rcv.sb_flags |= SB_UPCALL;
131 }
132
133 if (sa && from)
134 {
135 if (fromlen > sa->sa_len) fromlen = sa->sa_len;
136 memcpy(from, sa, fromlen);
137 }
138 if (sa) FREE(sa, M_SONAME);
139 *new_sock = new_so;
140 if (dosocklock)
141 socket_unlock(new_so, 1);
142 return error;
143}
144
145errno_t
146sock_bind(
147 socket_t sock,
148 const struct sockaddr *to)
149{
150 if (sock == NULL || to == NULL) return EINVAL;
151
152 return sobind(sock, (struct sockaddr*)to);
153}
154
155errno_t
156sock_connect(
157 socket_t sock,
158 const struct sockaddr *to,
159 int flags)
160{
161 int error = 0;
162 lck_mtx_t *mutex_held;
163
164 if (sock == NULL || to == NULL) return EINVAL;
165
166 socket_lock(sock, 1);
167
168 if ((sock->so_state & SS_ISCONNECTING) &&
169 ((sock->so_state & SS_NBIO) != 0 ||
170 (flags & MSG_DONTWAIT) != 0)) {
171 socket_unlock(sock, 1);
172 return EALREADY;
173 }
174 error = soconnectlock(sock, (struct sockaddr*)to, 0);
175 if (!error) {
176 if ((sock->so_state & SS_ISCONNECTING) &&
177 ((sock->so_state & SS_NBIO) != 0 || (flags & MSG_DONTWAIT) != 0)) {
178 socket_unlock(sock, 1);
179 return EINPROGRESS;
180 }
181
182 if (sock->so_proto->pr_getlock != NULL)
183 mutex_held = (*sock->so_proto->pr_getlock)(sock, 0);
184 else
185 mutex_held = sock->so_proto->pr_domain->dom_mtx;
186
187 while ((sock->so_state & SS_ISCONNECTING) && sock->so_error == 0) {
188 error = msleep((caddr_t)&sock->so_timeo, mutex_held, PSOCK | PCATCH,
189 "sock_connect", 0);
190 if (error)
191 break;
192 }
193
194 if (error == 0) {
195 error = sock->so_error;
196 sock->so_error = 0;
197 }
198 }
199 else {
200 sock->so_state &= ~SS_ISCONNECTING;
201 }
202 socket_unlock(sock, 1);
203 return error;
204}
205
206errno_t
207sock_connectwait(
208 socket_t sock,
209 const struct timeval *tv)
210{
211 lck_mtx_t * mutex_held;
212 errno_t retval = 0;
213 struct timespec ts;
214
215 socket_lock(sock, 1);
216
217 // Check if we're already connected or if we've already errored out
218 if ((sock->so_state & SS_ISCONNECTING) == 0 || sock->so_error) {
219 if (sock->so_error) {
220 retval = sock->so_error;
221 sock->so_error = 0;
222 }
223 else {
224 if ((sock->so_state & SS_ISCONNECTED) != 0)
225 retval = 0;
226 else
227 retval = EINVAL;
228 }
229 goto done;
230 }
231
232 // copied translation from timeval to hertz from SO_RCVTIMEO handling
233 if (tv->tv_sec < 0 || tv->tv_sec > SHRT_MAX / hz ||
234 tv->tv_usec < 0 || tv->tv_usec >= 1000000) {
235 retval = EDOM;
236 goto done;
237 }
238
239 ts.tv_sec = tv->tv_sec;
240 ts.tv_nsec = (tv->tv_usec * NSEC_PER_USEC);
241 if ( (ts.tv_sec + (ts.tv_nsec/NSEC_PER_SEC))/100 > SHRT_MAX) {
242 retval = EDOM;
243 goto done;
244 }
245
246 if (sock->so_proto->pr_getlock != NULL)
247 mutex_held = (*sock->so_proto->pr_getlock)(sock, 0);
248 else
249 mutex_held = sock->so_proto->pr_domain->dom_mtx;
250
251 msleep((caddr_t)&sock->so_timeo, mutex_held, PSOCK, "sock_connectwait", &ts);
252
253 // Check if we're still waiting to connect
254 if ((sock->so_state & SS_ISCONNECTING) && sock->so_error == 0) {
255 retval = EINPROGRESS;
256 goto done;
257 }
258
259 if (sock->so_error) {
260 retval = sock->so_error;
261 sock->so_error = 0;
262 }
263
264done:
265 socket_unlock(sock, 1);
266 return retval;
267}
268
269errno_t
270sock_nointerrupt(
271 socket_t sock,
272 int on)
273{
274 socket_lock(sock, 1);
275
276 if (on) {
277 sock->so_rcv.sb_flags |= SB_NOINTR; // This isn't safe
278 sock->so_snd.sb_flags |= SB_NOINTR; // This isn't safe
279 }
280 else {
281 sock->so_rcv.sb_flags &= ~SB_NOINTR; // This isn't safe
282 sock->so_snd.sb_flags &= ~SB_NOINTR; // This isn't safe
283 }
284
285 socket_unlock(sock, 1);
286
287 return 0;
288}
289
290errno_t
291sock_getpeername(
292 socket_t sock,
293 struct sockaddr *peername,
294 int peernamelen)
295{
296 int error = 0;
297 struct sockaddr *sa = NULL;
298
299 if (sock == NULL || peername == NULL || peernamelen < 0) return EINVAL;
300 socket_lock(sock, 1);
301 if ((sock->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) {
302 socket_unlock(sock, 1);
303 return ENOTCONN;
304 }
305 error = sock->so_proto->pr_usrreqs->pru_peeraddr(sock, &sa);
306 if (!error)
307 {
308 if (peernamelen > sa->sa_len) peernamelen = sa->sa_len;
309 memcpy(peername, sa, peernamelen);
310 }
311 if (sa) FREE(sa, M_SONAME);
312 socket_unlock(sock, 1);
313 return error;
314}
315
316errno_t
317sock_getsockname(
318 socket_t sock,
319 struct sockaddr *sockname,
320 int socknamelen)
321{
322 int error = 0;
323 struct sockaddr *sa = NULL;
324
325 if (sock == NULL || sockname == NULL || socknamelen < 0) return EINVAL;
326 socket_lock(sock, 1);
327 error = sock->so_proto->pr_usrreqs->pru_sockaddr(sock, &sa);
328 if (!error)
329 {
330 if (socknamelen > sa->sa_len) socknamelen = sa->sa_len;
331 memcpy(sockname, sa, socknamelen);
332 }
333 if (sa) FREE(sa, M_SONAME);
334 socket_unlock(sock, 1);
335 return error;
336}
337
338errno_t
339sock_getsockopt(
340 socket_t sock,
341 int level,
342 int optname,
343 void *optval,
344 int *optlen)
345{
346 int error = 0;
347 struct sockopt sopt;
348
349 if (sock == NULL || optval == NULL || optlen == NULL) return EINVAL;
350 sopt.sopt_dir = SOPT_GET;
351 sopt.sopt_level = level;
352 sopt.sopt_name = optname;
353 sopt.sopt_val = CAST_USER_ADDR_T(optval);
354 sopt.sopt_valsize = *optlen;
355 sopt.sopt_p = NULL;
356 error = sogetopt(sock, &sopt); /* will lock socket */
357 if (error == 0) *optlen = sopt.sopt_valsize;
358 return error;
359}
360
361errno_t
362sock_ioctl(
363 socket_t sock,
364 unsigned long request,
365 void *argp)
366{
367 return soioctl(sock, request, argp, NULL); /* will lock socket */
368}
369
370errno_t
371sock_setsockopt(
372 socket_t sock,
373 int level,
374 int optname,
375 const void *optval,
376 int optlen)
377{
378 struct sockopt sopt;
379
380 if (sock == NULL || optval == NULL) return EINVAL;
381 sopt.sopt_dir = SOPT_SET;
382 sopt.sopt_level = level;
383 sopt.sopt_name = optname;
384 sopt.sopt_val = CAST_USER_ADDR_T(optval);
385 sopt.sopt_valsize = optlen;
386 sopt.sopt_p = NULL;
387 return sosetopt(sock, &sopt); /* will lock socket */
388}
389
390errno_t
391sock_listen(
392 socket_t sock,
393 int backlog)
394{
395 if (sock == NULL) return EINVAL;
396 return solisten(sock, backlog); /* will lock socket */
397}
398
399static errno_t
400sock_receive_internal(
401 socket_t sock,
402 struct msghdr *msg,
403 mbuf_t *data,
404 int flags,
405 size_t *recvdlen)
406{
407 uio_t auio;
408 struct mbuf *control = NULL;
409 int error = 0;
410 int length = 0;
411 struct sockaddr *fromsa;
412 char uio_buf[ UIO_SIZEOF((msg != NULL) ? msg->msg_iovlen : 0) ];
413
414 if (sock == NULL) return EINVAL;
415
416 auio = uio_createwithbuffer(((msg != NULL) ? msg->msg_iovlen : 0),
417 0, UIO_SYSSPACE, UIO_READ,
418 &uio_buf[0], sizeof(uio_buf));
419 if (msg && data == NULL) {
420 int i;
421 struct iovec_32 *tempp = (struct iovec_32 *) msg->msg_iov;
422
423 for (i = 0; i < msg->msg_iovlen; i++) {
424 uio_addiov(auio, CAST_USER_ADDR_T((tempp + i)->iov_base), (tempp + i)->iov_len);
425 }
426 if (uio_resid(auio) < 0) return EINVAL;
427 }
428 else {
429 uio_setresid(auio, (uio_resid(auio) + *recvdlen));
430 }
431 length = uio_resid(auio);
432
433 if (recvdlen)
434 *recvdlen = 0;
435
436 if (msg && msg->msg_control) {
437 if ((size_t)msg->msg_controllen < sizeof(struct cmsghdr)) return EINVAL;
438 if ((size_t)msg->msg_controllen > MLEN) return EINVAL;
439 control = m_get(M_NOWAIT, MT_CONTROL);
440 if (control == NULL) return ENOMEM;
441 memcpy(mtod(control, caddr_t), msg->msg_control, msg->msg_controllen);
442 control->m_len = msg->msg_controllen;
443 }
444
445 /* let pru_soreceive handle the socket locking */
446 error = sock->so_proto->pr_usrreqs->pru_soreceive(sock, &fromsa, auio,
447 data, control ? &control : NULL, &flags);
448 if (error) goto cleanup;
449
450 if (recvdlen)
451 *recvdlen = length - uio_resid(auio);
452 if (msg) {
453 msg->msg_flags = flags;
454
455 if (msg->msg_name)
456 {
457 int salen;
458 salen = msg->msg_namelen;
459 if (msg->msg_namelen > 0 && fromsa != 0)
460 {
461 salen = MIN(salen, fromsa->sa_len);
462 memcpy(msg->msg_name, fromsa,
463 msg->msg_namelen > fromsa->sa_len ? fromsa->sa_len : msg->msg_namelen);
464 }
465 }
466
467 if (msg->msg_control)
468 {
469 struct mbuf* m = control;
470 u_char* ctlbuf = msg->msg_control;
471 int clen = msg->msg_controllen;
472 msg->msg_controllen = 0;
473
474 while (m && clen > 0)
475 {
476 unsigned int tocopy;
477 if (clen >= m->m_len)
478 {
479 tocopy = m->m_len;
480 }
481 else
482 {
483 msg->msg_flags |= MSG_CTRUNC;
484 tocopy = clen;
485 }
486 memcpy(ctlbuf, mtod(m, caddr_t), tocopy);
487 ctlbuf += tocopy;
488 clen -= tocopy;
489 m = m->m_next;
490 }
491 msg->msg_controllen = (u_int32_t)ctlbuf - (u_int32_t)msg->msg_control;
492 }
493 }
494
495cleanup:
496 if (control) m_freem(control);
497 if (fromsa) FREE(fromsa, M_SONAME);
498 return error;
499}
500
501errno_t
502sock_receive(
503 socket_t sock,
504 struct msghdr *msg,
505 int flags,
506 size_t *recvdlen)
507{
508 if ((msg == NULL) ||
509 (msg->msg_iovlen < 1) ||
510 (msg->msg_iov[0].iov_len == 0) ||
511 (msg->msg_iov[0].iov_base == NULL))
512 return EINVAL;
513 return sock_receive_internal(sock, msg, NULL, flags, recvdlen);
514}
515
516errno_t
517sock_receivembuf(
518 socket_t sock,
519 struct msghdr *msg,
520 mbuf_t *data,
521 int flags,
522 size_t *recvlen)
523{
524 if (data == NULL || recvlen == 0 || *recvlen <= 0 || (msg &&
525 (msg->msg_iov != NULL || msg->msg_iovlen != 0)))
526 return EINVAL;
527 return sock_receive_internal(sock, msg, data, flags, recvlen);
528}
529
530errno_t
531sock_send_internal(
532 socket_t sock,
533 const struct msghdr *msg,
534 mbuf_t data,
535 int flags,
536 size_t *sentlen)
537{
538 uio_t auio = NULL;
539 struct mbuf *control = NULL;
540 int error = 0;
541 int datalen = 0;
542 char uio_buf[ UIO_SIZEOF((msg != NULL ? msg->msg_iovlen : 1)) ];
543
544 if (sock == NULL) {
545 error = EINVAL;
546 goto errorout;
547 }
548
549 if (data == 0 && msg != NULL) {
550 struct iovec_32 *tempp = (struct iovec_32 *) msg->msg_iov;
551
552 auio = uio_createwithbuffer(msg->msg_iovlen, 0, UIO_SYSSPACE, UIO_WRITE,
553 &uio_buf[0], sizeof(uio_buf));
554 if (tempp != NULL)
555 {
556 int i;
557
558 for (i = 0; i < msg->msg_iovlen; i++) {
559 uio_addiov(auio, CAST_USER_ADDR_T((tempp + i)->iov_base), (tempp + i)->iov_len);
560 }
561
562 if (uio_resid(auio) < 0) {
563 error = EINVAL;
564 goto errorout;
565 }
566 }
567 }
568
569 if (sentlen)
570 *sentlen = 0;
571
572 if (auio)
573 datalen = uio_resid(auio);
574 else
575 datalen = data->m_pkthdr.len;
576
577 if (msg && msg->msg_control)
578 {
579 if ((size_t)msg->msg_controllen < sizeof(struct cmsghdr)) return EINVAL;
580 if ((size_t)msg->msg_controllen > MLEN) return EINVAL;
581 control = m_get(M_NOWAIT, MT_CONTROL);
582 if (control == NULL) {
583 error = ENOMEM;
584 goto errorout;
585 }
586 memcpy(mtod(control, caddr_t), msg->msg_control, msg->msg_controllen);
587 control->m_len = msg->msg_controllen;
588 }
589
590 error = sock->so_proto->pr_usrreqs->pru_sosend(sock, msg ? (struct sockaddr*)msg->msg_name : 0,
591 auio, data, control, flags);
592 if (error == 0 && sentlen) {
593 if (auio)
594 *sentlen = datalen - uio_resid(auio);
595 else
596 *sentlen = datalen;
597 }
598
599 return error;
600
601/*
602 * In cases where we detect an error before returning, we need to
603 * free the mbuf chain if there is one. sosend (and pru_sosend) will
604 * free the mbuf chain if they encounter an error.
605 */
606errorout:
607 if (control)
608 m_freem(control);
609 if (data)
610 m_freem(data);
611 if (sentlen)
612 *sentlen = 0;
613 return error;
614}
615
616errno_t
617sock_send(
618 socket_t sock,
619 const struct msghdr *msg,
620 int flags,
621 size_t *sentlen)
622{
623 if (msg == NULL || msg->msg_iov == NULL || msg->msg_iovlen < 1)
624 return EINVAL;
625 return sock_send_internal(sock, msg, NULL, flags, sentlen);
626}
627
628errno_t
629sock_sendmbuf(
630 socket_t sock,
631 const struct msghdr *msg,
632 mbuf_t data,
633 int flags,
634 size_t *sentlen)
635{
636 if (data == NULL || (msg &&
637 (msg->msg_iov != NULL || msg->msg_iovlen != 0))) {
638 if (data)
639 m_freem(data);
640 return EINVAL;
641 }
642 return sock_send_internal(sock, msg, data, flags, sentlen);
643}
644
645errno_t
646sock_shutdown(
647 socket_t sock,
648 int how)
649{
650 if (sock == NULL) return EINVAL;
651 return soshutdown(sock, how);
652}
653
654typedef void (*so_upcall)(struct socket *sock, void* arg, int waitf);
655
656errno_t
657sock_socket(
658 int domain,
659 int type,
660 int protocol,
661 sock_upcall callback,
662 void* context,
663 socket_t *new_so)
664{
665 int error = 0;
666 if (new_so == NULL) return EINVAL;
667 /* socreate will create an initial so_count */
668 error = socreate(domain, new_so, type, protocol);
669 if (error == 0 && callback)
670 {
671 (*new_so)->so_rcv.sb_flags |= SB_UPCALL;
672 (*new_so)->so_upcall = (so_upcall)callback;
673 (*new_so)->so_upcallarg = context;
674 }
675 return error;
676}
677
678void
679sock_close(
680 socket_t sock)
681{
682 if (sock == NULL) return;
683 soclose(sock);
684}
685
686/* Do we want this to be APPLE_PRIVATE API?: YES (LD 12/23/04)*/
687void
688sock_retain(
689 socket_t sock)
690{
691 if (sock == NULL) return;
692 socket_lock(sock, 1);
693 sock->so_retaincnt++;
694 sock->so_usecount++; /* add extra reference for holding the socket */
695 socket_unlock(sock, 1);
696}
697
698/* Do we want this to be APPLE_PRIVATE API? */
699void
700sock_release(
701 socket_t sock)
702{
703 if (sock == NULL) return;
704 socket_lock(sock, 1);
705 sock->so_retaincnt--;
706 if (sock->so_retaincnt < 0)
707 panic("sock_release: negative retain count for sock=%x cnt=%x\n",
708 sock, sock->so_retaincnt);
709 if ((sock->so_retaincnt == 0) && (sock->so_usecount == 2))
710 soclose_locked(sock); /* close socket only if the FD is not holding it */
711 else
712 sock->so_usecount--; /* remove extra reference holding the socket */
713 socket_unlock(sock, 1);
714}
715
716errno_t
717sock_setpriv(
718 socket_t sock,
719 int on)
720{
721 if (sock == NULL) return EINVAL;
722 socket_lock(sock, 1);
723 if (on)
724 {
725 sock->so_state |= SS_PRIV;
726 }
727 else
728 {
729 sock->so_state &= ~SS_PRIV;
730 }
731 socket_unlock(sock, 1);
732 return 0;
733}
734
735int
736sock_isconnected(
737 socket_t sock)
738{
739 int retval;
740 socket_lock(sock, 1);
741 retval = (sock->so_state & SS_ISCONNECTED) != 0;
742 socket_unlock(sock, 1);
743 return (retval);
744}
745
746int
747sock_isnonblocking(
748 socket_t sock)
749{
750 int retval;
751 socket_lock(sock, 1);
752 retval = (sock->so_state & SS_NBIO) != 0;
753 socket_unlock(sock, 1);
754 return (retval);
755}
756
757errno_t
758sock_gettype(
759 socket_t sock,
760 int *outDomain,
761 int *outType,
762 int *outProtocol)
763{
764 socket_lock(sock, 1);
765 if (outDomain)
766 *outDomain = sock->so_proto->pr_domain->dom_family;
767 if (outType)
768 *outType = sock->so_type;
769 if (outProtocol)
770 *outProtocol = sock->so_proto->pr_protocol;
771 socket_unlock(sock, 1);
772 return 0;
773}