|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
26: /*
27: * Copyright (c) 1982, 1986, 1988, 1990, 1993
28: * The Regents of the University of California. All rights reserved.
29: *
30: * Redistribution and use in source and binary forms, with or without
31: * modification, are permitted provided that the following conditions
32: * are met:
33: * 1. Redistributions of source code must retain the above copyright
34: * notice, this list of conditions and the following disclaimer.
35: * 2. Redistributions in binary form must reproduce the above copyright
36: * notice, this list of conditions and the following disclaimer in the
37: * documentation and/or other materials provided with the distribution.
38: * 3. All advertising materials mentioning features or use of this software
39: * must display the following acknowledgement:
40: * This product includes software developed by the University of
41: * California, Berkeley and its contributors.
42: * 4. Neither the name of the University nor the names of its contributors
43: * may be used to endorse or promote products derived from this software
44: * without specific prior written permission.
45: *
46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56: * SUCH DAMAGE.
57: *
58: * @(#)uipc_socket.c 8.6 (Berkeley) 5/2/95
59: */
60:
61: #include <sys/param.h>
62: #include <sys/systm.h>
63: #include <sys/proc.h>
64: #include <sys/file.h>
65: #include <sys/malloc.h>
66: #include <sys/mbuf.h>
67: #include <sys/domain.h>
68: #include <sys/time.h>
69: #include <sys/kernel.h>
70: #include <sys/protosw.h>
71: #include <sys/socket.h>
72: #include <sys/socketvar.h>
73: #include <sys/resourcevar.h>
74: #include <net/route.h>
75: #include <net/if.h>
76: #include <netinet/in.h>
77: #include <netinet/in_systm.h>
78: #include <netinet/ip.h>
79: #include <netinet/in_pcb.h>
80: #include <machine/spl.h>
81:
82: #if NEXT
83: #import <kern/kdebug.h>
84:
85: #if KDEBUG
86:
87: #define DBG_LAYER_IN_BEG NETDBG_CODE(DBG_NETSOCK, 0)
88: #define DBG_LAYER_IN_END NETDBG_CODE(DBG_NETSOCK, 2)
89: #define DBG_LAYER_OUT_BEG NETDBG_CODE(DBG_NETSOCK, 1)
90: #define DBG_LAYER_OUT_END NETDBG_CODE(DBG_NETSOCK, 3)
91: #define DBG_FNC_SOSEND NETDBG_CODE(DBG_NETSOCK, (4 << 8) | 1)
92: #define DBG_FNC_SORECEIVE NETDBG_CODE(DBG_NETSOCK, (8 << 8))
93:
94: #endif
95: #endif
96:
97:
98: int so_cache_hw = 0;
99: int so_cache_timeouts = 0;
100: int so_cache_max_freed = 0;
101: int cached_sock_count = 0;
102: struct socket *socket_cache_head = 0;
103: struct socket *socket_cache_tail = 0;
104: u_long so_cache_time = 0;
105: int so_cache_init_done = 0;
106: struct zone *so_cache_zone;
107: extern int get_inpcb_str_size();
108: extern int get_tcp_str_size();
109:
110: void so_cache_timer();
111:
112: /*
113: * Socket operation routines.
114: * These routines are called by the routines in
115: * sys_socket.c or from a system process, and
116: * implement the semantics of socket operations by
117: * switching out to the protocol specific routines.
118: */
119: /*ARGSUSED*/
120:
121:
122: void socketinit()
123: {
124: vm_size_t str_size;
125:
126: so_cache_init_done = 1;
127:
128: timeout(so_cache_timer, NULL, (SO_CACHE_FLUSH_INTERVAL * hz));
129: str_size = (vm_size_t)( sizeof(struct socket) + 4 +
130: get_inpcb_str_size() + 4 +
131: get_tcp_str_size());
132: so_cache_zone = zinit (str_size, 120000*str_size, 8192, FALSE, "socache zone");
133: #if TEMPDEBUG
134: kprintf("cached_sock_alloc -- so_cache_zone size is %x\n", str_size);
135: #endif
136:
137: }
138:
139:
140: void cached_sock_alloc(so)
141: struct socket **so;
142: {
143: caddr_t temp;
144: int s;
145: register u_long offset;
146:
147:
148: s = splnet();
149: if (cached_sock_count) {
150: cached_sock_count--;
151: *so = socket_cache_head;
152: if (*so == 0)
153: panic("cached_sock_alloc: cached sock is null");
154:
155: socket_cache_head = socket_cache_head->cache_next;
156: if (socket_cache_head)
157: socket_cache_head->cache_prev = 0;
158: else
159: socket_cache_tail = 0;
160: splx(s);
161:
162: temp = (*so)->so_saved_pcb;
163: bzero((caddr_t)*so, sizeof(struct socket));
164: #if TEMPDEBUG
165: kprintf("cached_sock_alloc - retreiving cached sock %x - count == %d\n", *so,
166: cached_sock_count);
167: #endif
168: (*so)->so_saved_pcb = temp;
169: }
170: else {
171: #if TEMPDEBUG
172: kprintf("Allocating cached sock %x from memory\n", *so);
173: #endif
174:
175: splx(s);
176: *so = (caddr_t) zalloc(so_cache_zone);
177: if (*so == 0)
178: panic("cached_sock_alloc -- Out of zone space");
179:
180: bzero((caddr_t)*so, sizeof(struct socket));
181:
182: /*
183: * Define offsets for extra structures into our single block of
184: * memory. Align extra structures on longword boundaries.
185: */
186:
187:
188: offset = *so;
189: offset += sizeof(struct socket);
190: if (offset & 0x3) {
191: offset += 4;
192: offset &= 0xfffffffc;
193: }
194: (*so)->so_saved_pcb = offset;
195: offset += get_inpcb_str_size();
196: if (offset & 0x3) {
197: offset += 4;
198: offset &= 0xfffffffc;
199: }
200:
201: ((struct inpcb *) (*so)->so_saved_pcb)->inp_saved_ppcb = offset;
202: #if TEMPDEBUG
203: kprintf("Allocating cached socket - %x, pcb=%x tcpcb=%x\n", *so,
204: (*so)->so_saved_pcb,
205: ((struct inpcb *)(*so)->so_saved_pcb)->inp_saved_ppcb);
206: #endif
207: }
208:
209: (*so)->cached_in_sock_layer = 1;
210: }
211:
212:
213: void cached_sock_free(so)
214: struct socket *so;
215: {
216: int s;
217:
218:
219: s = splnet();
220: if (++cached_sock_count > MAX_CACHED_SOCKETS) {
221: --cached_sock_count;
222: splx(s);
223: #if TEMPDEBUG
224: kprintf("Freeing overflowed cached socket %x\n", so);
225: #endif
226: zfree(so_cache_zone, (vm_offset_t) so);
227: }
228: else {
229: #if TEMPDEBUG
230: kprintf("Freeing socket %x into cache\n", so);
231: #endif
232: if (so_cache_hw < cached_sock_count)
233: so_cache_hw = cached_sock_count;
234:
235: so->cache_next = socket_cache_head;
236: so->cache_prev = 0;
237: if (socket_cache_head)
238: socket_cache_head->cache_prev = so;
239: else
240: socket_cache_tail = so;
241:
242: so->cache_timestamp = so_cache_time;
243: socket_cache_head = so;
244: splx(s);
245: }
246:
247: #if TEMPDEBUG
248: kprintf("Freed cached sock %x into cache - count is %d\n", so, cached_sock_count);
249: #endif
250:
251:
252: }
253:
254:
255: void so_cache_timer()
256: {
257: register struct socket *p;
258: register int s;
259: register int n_freed = 0;
260:
261:
262: ++so_cache_time;
263:
264: s = splnet();
265:
266: while (p = socket_cache_tail)
267: {
268: if ((so_cache_time - p->cache_timestamp) < SO_CACHE_TIME_LIMIT)
269: break;
270:
271: so_cache_timeouts++;
272:
273: if (socket_cache_tail = p->cache_prev)
274: p->cache_prev->cache_next = 0;
275: if (--cached_sock_count == 0)
276: socket_cache_head = 0;
277:
278: splx(s);
279:
280: zfree(so_cache_zone, (vm_offset_t) p);
281:
282: splnet();
283: if (++n_freed >= SO_CACHE_MAX_FREE_BATCH)
284: {
285: so_cache_max_freed++;
286: break;
287: }
288: }
289: splx(s);
290:
291: timeout(so_cache_timer, NULL, (SO_CACHE_FLUSH_INTERVAL * hz));
292: }
293:
294:
295:
296: int
297: socreate(dom, aso, type, proto)
298: int dom;
299: struct socket **aso;
300: register int type;
301: int proto;
302: {
303: struct proc *p = current_proc(); /* XXX */
304: register struct protosw *prp;
305: register struct socket *so;
306: register int error;
307:
308: if (proto)
309: prp = pffindproto(dom, proto, type);
310: else
311: prp = pffindtype(dom, type);
312: if (prp == 0 || prp->pr_usrreq == 0)
313: return (EPROTONOSUPPORT);
314: if (prp->pr_type != type)
315: return (EPROTOTYPE);
316:
317: #ifdef SOCKET_CACHE_ON
318: if ((dom == PF_INET) && (type == SOCK_STREAM))
319: cached_sock_alloc(&so);
320: else
321: #endif
322: {
323: MALLOC_ZONE(so, struct socket *, sizeof(*so), M_SOCKET, M_WAITOK);
324: bzero((caddr_t)so, sizeof(*so));
325: }
326:
327: so->so_type = type;
328: if (p->p_ucred->cr_uid == 0)
329: so->so_state = SS_PRIV;
330: so->so_proto = prp;
331: error =
332: (*prp->pr_usrreq)(so, PRU_ATTACH, (struct mbuf *)0,
333: (struct mbuf *)(long)proto, (struct mbuf *)0);
334: if (error) {
335: #if TEMPDEBUG
336: kprintf("SOCREATE - error on PRU_ATTACH for socket %x\n", so);
337: #endif
338: so->so_state |= SS_NOFDREF;
339: sofree(so);
340: return (error);
341: }
342: so->so_rcv.sb_flags |= SB_RECV;
343: so->so_rcv.sb_so = so->so_snd.sb_so = so;
344: TAILQ_INIT(&so->so_evlist);
345: *aso = so;
346: return (0);
347: }
348:
349: int
350: sobind(so, nam)
351: struct socket *so;
352: struct mbuf *nam;
353: {
354: int s = splnet();
355: int error;
356:
357: error =
358: (*so->so_proto->pr_usrreq)(so, PRU_BIND,
359: (struct mbuf *)0, nam, (struct mbuf *)0);
360: splx(s);
361: return (error);
362: }
363:
364: int
365: solisten(so, backlog)
366: register struct socket *so;
367: int backlog;
368: {
369: int s = splnet(), error;
370:
371: error =
372: (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
373: (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
374: if (error) {
375: splx(s);
376: return (error);
377: }
378: if (so->so_q == 0)
379: so->so_options |= SO_ACCEPTCONN;
380: if (backlog < 0)
381: backlog = 0;
382: so->so_qlimit = min(backlog, SOMAXCONN);
383: splx(s);
384: return (0);
385: }
386:
387: int
388: sofree(so)
389: register struct socket *so;
390: {
391:
392: if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
393: return;
394: if (so->so_head) {
395: if (!soqremque(so, 0) && !soqremque(so, 1))
396: panic("sofree dq");
397: so->so_head = 0;
398: }
399: sbrelease(&so->so_snd);
400: sorflush(so);
401:
402: if (so->cached_in_sock_layer == 1)
403: cached_sock_free(so);
404: else
405: FREE_ZONE(so, sizeof *so, M_SOCKET);
406: }
407:
408: /*
409: * Close a socket on last file table reference removal.
410: * Initiate disconnect if connected.
411: * Free socket when disconnect complete.
412: */
413: int
414: soclose(so)
415: register struct socket *so;
416: {
417: int s = splnet(); /* conservative */
418: int error = 0;
419:
420: if (so->so_options & SO_ACCEPTCONN) {
421: while (so->so_q0)
422: (void) soabort(so->so_q0);
423: while (so->so_q)
424: (void) soabort(so->so_q);
425: }
426: if (so->so_pcb == 0)
427: goto discard;
428: if (so->so_state & SS_ISCONNECTED) {
429: if ((so->so_state & SS_ISDISCONNECTING) == 0) {
430: error = sodisconnect(so);
431: if (error)
432: goto drop;
433: }
434: if (so->so_options & SO_LINGER) {
435: if ((so->so_state & SS_ISDISCONNECTING) &&
436: (so->so_state & SS_NBIO))
437: goto drop;
438: while (so->so_state & SS_ISCONNECTED)
439: if (error = tsleep((caddr_t)&so->so_timeo,
440: PSOCK | PCATCH, netcls, so->so_linger))
441: break;
442: }
443: }
444: drop:
445: if (so->so_pcb) {
446: int error2 =
447: (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
448: (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
449: if (error == 0)
450: error = error2;
451: }
452: discard:
453:
454: if (so->so_state & SS_NOFDREF)
455: panic("soclose: NOFDREF");
456: so->so_state |= SS_NOFDREF;
457: evsofree(so);
458: sofree(so);
459: splx(s);
460: return (error);
461: }
462:
463: /*
464: * Must be called at splnet...
465: */
466: int
467: soabort(so)
468: struct socket *so;
469: {
470:
471: return (
472: (*so->so_proto->pr_usrreq)(so, PRU_ABORT,
473: (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
474: }
475:
476: int
477: soaccept(so, nam)
478: register struct socket *so;
479: struct mbuf *nam;
480: {
481: int s = splnet();
482: int error;
483:
484: if ((so->so_state & SS_NOFDREF) == 0)
485: panic("soaccept: !NOFDREF");
486: so->so_state &= ~SS_NOFDREF;
487: error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
488: (struct mbuf *)0, nam, (struct mbuf *)0);
489: splx(s);
490: return (error);
491: }
492:
493: int
494: soconnect(so, nam)
495: register struct socket *so;
496: struct mbuf *nam;
497: {
498: int s;
499: int error;
500:
501: if (so->so_options & SO_ACCEPTCONN)
502: return (EOPNOTSUPP);
503: s = splnet();
504: /*
505: * If protocol is connection-based, can only connect once.
506: * Otherwise, if connected, try to disconnect first.
507: * This allows user to disconnect by connecting to, e.g.,
508: * a null address.
509: */
510: if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
511: ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
512: (error = sodisconnect(so))))
513: error = EISCONN;
514: else
515: error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
516: (struct mbuf *)0, nam, (struct mbuf *)0);
517: splx(s);
518: return (error);
519: }
520:
521: int
522: soconnect2(so1, so2)
523: register struct socket *so1;
524: struct socket *so2;
525: {
526: int s = splnet();
527: int error;
528:
529: error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2,
530: (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0);
531: splx(s);
532: return (error);
533: }
534:
535: int
536: sodisconnect(so)
537: register struct socket *so;
538: {
539: int s = splnet();
540: int error;
541:
542: if ((so->so_state & SS_ISCONNECTED) == 0) {
543: error = ENOTCONN;
544: goto bad;
545: }
546: if (so->so_state & SS_ISDISCONNECTING) {
547: error = EALREADY;
548: goto bad;
549: }
550: error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
551: (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
552: bad:
553: splx(s);
554: return (error);
555: }
556:
557: #define SBLOCKWAIT(f) (((f) & MSG_DONTWAIT) ? M_DONTWAIT : M_WAIT)
558: /*
559: * Send on a socket.
560: * If send must go all at once and message is larger than
561: * send buffering, then hard error.
562: * Lock against other senders.
563: * If must go all at once and not enough room now, then
564: * inform user that this would block and do nothing.
565: * Otherwise, if nonblocking, send as much as possible.
566: * The data to be sent is described by "uio" if nonzero,
567: * otherwise by the mbuf chain "top" (which must be null
568: * if uio is not). Data provided in mbuf chain must be small
569: * enough to send all at once.
570: *
571: * Returns nonzero on error, timeout or signal; callers
572: * must check for short counts if EINTR/ERESTART are returned.
573: * Data and control buffers are freed on return.
574: */
575: int
576: sosend(so, addr, uio, top, control, flags)
577: register struct socket *so;
578: struct mbuf *addr;
579: struct uio *uio;
580: struct mbuf *top;
581: struct mbuf *control;
582: int flags;
583: {
584:
585:
586: struct proc *p = current_proc(); /* XXX */
587: struct mbuf **mp;
588: register struct mbuf *m;
589: register long space, len, resid;
590: int clen = 0, error, s, dontroute, mlen;
591: int atomic = sosendallatonce(so) || top;
592:
593: if (uio)
594: resid = uio->uio_resid;
595: else
596: resid = top->m_pkthdr.len;
597:
598: KERNEL_DEBUG(DBG_FNC_SOSEND | DBG_FUNC_START,
599: so,
600: resid,
601: so->so_snd.sb_cc,
602: so->so_snd.sb_lowat,
603: so->so_snd.sb_hiwat);
604:
605: /*
606: * In theory resid should be unsigned.
607: * However, space must be signed, as it might be less than 0
608: * if we over-committed, and we must use a signed comparison
609: * of space and resid. On the other hand, a negative resid
610: * causes us to loop sending 0-length segments to the protocol.
611: */
612: if (resid < 0)
613: {
614: KERNEL_DEBUG(DBG_FNC_SOSEND | DBG_FUNC_END, EINVAL,0,0,0,0);
615: return (EINVAL);
616: }
617:
618: dontroute =
619: (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
620: (so->so_proto->pr_flags & PR_ATOMIC);
621: p->p_stats->p_ru.ru_msgsnd++;
622: if (control)
623: clen = control->m_len;
624: #define snderr(errno) { error = errno; splx(s); goto release; }
625:
626: restart:
627: if (error = sblock(&so->so_snd, SBLOCKWAIT(flags)))
628: goto out;
629: do {
630: s = splnet();
631: if (so->so_state & SS_CANTSENDMORE)
632: snderr(EPIPE);
633: if (so->so_error)
634: snderr(so->so_error);
635: if ((so->so_state & SS_ISCONNECTED) == 0) {
636: if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
637: if ((so->so_state & SS_ISCONFIRMING) == 0 &&
638: !(resid == 0 && clen != 0))
639: snderr(ENOTCONN);
640: } else if (addr == 0)
641: snderr(EDESTADDRREQ);
642: }
643: space = sbspace(&so->so_snd);
644: if (flags & MSG_OOB)
645: space += 1024;
646: if (atomic && resid > so->so_snd.sb_hiwat ||
647: clen > so->so_snd.sb_hiwat)
648: snderr(EMSGSIZE);
649: if (space < resid + clen && uio &&
650: (atomic || space < so->so_snd.sb_lowat || space < clen)) {
651: if (so->so_state & SS_NBIO)
652: snderr(EWOULDBLOCK);
653: sbunlock(&so->so_snd);
654: error = sbwait(&so->so_snd);
655: splx(s);
656: if (error)
657: goto out;
658: goto restart;
659: }
660: splx(s);
661: mp = ⊤
662: space -= clen;
663: do {
664: if (uio == NULL) {
665: /*
666: * Data is prepackaged in "top".
667: */
668: resid = 0;
669: if (flags & MSG_EOR)
670: top->m_flags |= M_EOR;
671: } else do {
672: if (top == 0) {
673: MGETHDR(m, M_WAIT, MT_DATA);
674: mlen = MHLEN;
675: m->m_pkthdr.len = 0;
676: m->m_pkthdr.rcvif = (struct ifnet *)0;
677: } else {
678: MGET(m, M_WAIT, MT_DATA);
679: mlen = MLEN;
680: }
681: if (resid >= MINCLSIZE) {
682: MCLGET(m, M_WAIT);
683: if ((m->m_flags & M_EXT) == 0)
684: goto nopages;
685: mlen = MCLBYTES;
686: len = min(min(mlen, resid), space);
687: } else {
688: nopages:
689: len = min(min(mlen, resid), space);
690: /*
691: * For datagram protocols, leave room
692: * for protocol headers in first mbuf.
693: */
694: if (atomic && top == 0 && len < mlen)
695: MH_ALIGN(m, len);
696: }
697: space -= len;
698: error = uiomove(mtod(m, caddr_t), (int)len, uio);
699: resid = uio->uio_resid;
700:
701: m->m_len = len;
702: *mp = m;
703: top->m_pkthdr.len += len;
704: if (error)
705: goto release;
706: mp = &m->m_next;
707: if (resid <= 0) {
708: if (flags & MSG_EOR)
709: top->m_flags |= M_EOR;
710: break;
711: }
712: } while (space > 0 && (atomic || resid < MINCLSIZE));
713:
714: if (dontroute)
715: so->so_options |= SO_DONTROUTE;
716: if (resid > 0)
717: so->so_state |= SS_MORETOCOME;
718: s = splnet(); /* XXX */
719: error = (*so->so_proto->pr_usrreq)(so,
720: (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
721: top, addr, control);
722: splx(s);
723: if (dontroute)
724: so->so_options &= ~SO_DONTROUTE;
725: so->so_state &= ~SS_MORETOCOME;
726: clen = 0;
727: control = 0;
728: top = 0;
729: mp = ⊤
730: if (error)
731: goto release;
732: } while (resid && space > 0);
733: } while (resid);
734:
735: release:
736: sbunlock(&so->so_snd);
737: out:
738: if (top)
739: m_freem(top);
740: if (control)
741: m_freem(control);
742:
743: KERNEL_DEBUG(DBG_FNC_SOSEND | DBG_FUNC_END,
744: so,
745: resid,
746: so->so_snd.sb_cc,
747: space,
748: error);
749:
750: return (error);
751: }
752:
753: /*
754: * Implement receive operations on a socket.
755: * We depend on the way that records are added to the sockbuf
756: * by sbappend*. In particular, each record (mbufs linked through m_next)
757: * must begin with an address if the protocol so specifies,
758: * followed by an optional mbuf or mbufs containing ancillary data,
759: * and then zero or more mbufs of data.
760: * In order to avoid blocking network interrupts for the entire time here,
761: * we splx() while doing the actual copy to user space.
762: * Although the sockbuf is locked, new data may still be appended,
763: * and thus we must maintain consistency of the sockbuf during that time.
764: *
765: * The caller may receive the data as a single mbuf chain by supplying
766: * an mbuf **mp0 for use in returning the chain. The uio is then used
767: * only for the count in uio_resid.
768: */
769: int
770: soreceive(so, paddr, uio, mp0, controlp, flagsp)
771: register struct socket *so;
772: struct mbuf **paddr;
773: struct uio *uio;
774: struct mbuf **mp0;
775: struct mbuf **controlp;
776: int *flagsp;
777: {
778: register struct mbuf *m, **mp;
779: register int flags, len, error, s, offset;
780: struct protosw *pr = so->so_proto;
781: struct mbuf *nextrecord;
782: int moff, type;
783: int orig_resid = uio->uio_resid;
784:
785:
786: KERNEL_DEBUG(DBG_FNC_SORECEIVE | DBG_FUNC_START,
787: so,
788: uio->uio_resid,
789: so->so_rcv.sb_cc,
790: so->so_rcv.sb_lowat,
791: so->so_rcv.sb_hiwat);
792: mp = mp0;
793: if (paddr)
794: *paddr = 0;
795: if (controlp)
796: *controlp = 0;
797: if (flagsp)
798: flags = *flagsp &~ MSG_EOR;
799: else
800: flags = 0;
801: if (flags & MSG_OOB) {
802: m = m_get(M_WAIT, MT_DATA);
803: error = (*pr->pr_usrreq)(so, PRU_RCVOOB, m,
804: (struct mbuf *)(long)(flags & MSG_PEEK), (struct mbuf *)0);
805: if (error)
806: goto bad;
807: do {
808: error = uiomove(mtod(m, caddr_t),
809: (int) min(uio->uio_resid, m->m_len), uio);
810: m = m_free(m);
811: } while (uio->uio_resid && error == 0 && m);
812: bad:
813: if (m)
814: m_freem(m);
815:
816: KERNEL_DEBUG(DBG_FNC_SORECEIVE | DBG_FUNC_END, error,0,0,0,0);
817: return (error);
818: }
819: if (mp)
820: *mp = (struct mbuf *)0;
821: if (so->so_state & SS_ISCONFIRMING && uio->uio_resid)
822: (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
823: (struct mbuf *)0, (struct mbuf *)0);
824:
825: restart:
826: if (error = sblock(&so->so_rcv, SBLOCKWAIT(flags)))
827: {
828: KERNEL_DEBUG(DBG_FNC_SORECEIVE | DBG_FUNC_END, error,0,0,0,0);
829: return (error);
830: }
831: s = splnet();
832:
833: m = so->so_rcv.sb_mb;
834: /*
835: * If we have less data than requested, block awaiting more
836: * (subject to any timeout) if:
837: * 1. the current count is less than the low water mark,
838: * 2. MSG_WAITALL is set, and it is possible to do the entire
839: * receive operation at once if we block (resid <= hiwat), or
840: * 3. MSG_DONTWAIT is not set.
841: * If MSG_WAITALL is set but resid is larger than the receive buffer,
842: * we have to do the receive in sections, and thus risk returning
843: * a short count if a timeout or signal occurs after we start.
844: */
845: if (m == 0 || ((flags & MSG_DONTWAIT) == 0 &&
846: so->so_rcv.sb_cc < uio->uio_resid) &&
847: (so->so_rcv.sb_cc < so->so_rcv.sb_lowat ||
848: ((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) &&
849: m->m_nextpkt == 0 && (pr->pr_flags & PR_ATOMIC) == 0) {
850: #if DIAGNOSTIC
851: if (m == 0 && so->so_rcv.sb_cc)
852: panic("receive 1");
853: #endif
854: if (so->so_error) {
855: if (m)
856: goto dontblock;
857: error = so->so_error;
858: if ((flags & MSG_PEEK) == 0)
859: so->so_error = 0;
860: goto release;
861: }
862: if (so->so_state & SS_CANTRCVMORE) {
863: if (m)
864: goto dontblock;
865: else
866: goto release;
867: }
868: for (; m; m = m->m_next)
869: if (m->m_type == MT_OOBDATA || (m->m_flags & M_EOR)) {
870: m = so->so_rcv.sb_mb;
871: goto dontblock;
872: }
873: if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 &&
874: (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
875: error = ENOTCONN;
876: goto release;
877: }
878: if (uio->uio_resid == 0)
879: goto release;
880: if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) {
881: error = EWOULDBLOCK;
882: goto release;
883: }
884: sbunlock(&so->so_rcv);
885: error = sbwait(&so->so_rcv);
886: splx(s);
887: if (error)
888: {
889: KERNEL_DEBUG(DBG_FNC_SORECEIVE | DBG_FUNC_END, error,0,0,0,0);
890: return (error);
891: }
892: goto restart;
893: }
894: dontblock:
895: #ifdef notyet /* XXXX */
896: if (uio->uio_procp)
897: uio->uio_procp->p_stats->p_ru.ru_msgrcv++;
898: #endif
899: nextrecord = m->m_nextpkt;
900: if (pr->pr_flags & PR_ADDR) {
901: #if DIAGNOSTIC
902: if (m->m_type != MT_SONAME)
903: panic("receive 1a");
904: #endif
905: orig_resid = 0;
906: if (flags & MSG_PEEK) {
907: if (paddr)
908: *paddr = m_copy(m, 0, m->m_len);
909: m = m->m_next;
910: } else {
911: sbfree(&so->so_rcv, m);
912: if (paddr) {
913: *paddr = m;
914: so->so_rcv.sb_mb = m->m_next;
915: m->m_next = 0;
916: m = so->so_rcv.sb_mb;
917: } else {
918: MFREE(m, so->so_rcv.sb_mb);
919: m = so->so_rcv.sb_mb;
920: }
921: }
922: }
923: while (m && m->m_type == MT_CONTROL && error == 0) {
924: if (flags & MSG_PEEK) {
925: if (controlp)
926: *controlp = m_copy(m, 0, m->m_len);
927: m = m->m_next;
928: } else {
929: sbfree(&so->so_rcv, m);
930: if (controlp) {
931: if (pr->pr_domain->dom_externalize &&
932: mtod(m, struct cmsghdr *)->cmsg_type ==
933: SCM_RIGHTS)
934: error = (*pr->pr_domain->dom_externalize)(m);
935: *controlp = m;
936: so->so_rcv.sb_mb = m->m_next;
937: m->m_next = 0;
938: m = so->so_rcv.sb_mb;
939: } else {
940: MFREE(m, so->so_rcv.sb_mb);
941: m = so->so_rcv.sb_mb;
942: }
943: }
944: if (controlp) {
945: orig_resid = 0;
946: controlp = &(*controlp)->m_next;
947: }
948: }
949: if (m) {
950: if ((flags & MSG_PEEK) == 0)
951: m->m_nextpkt = nextrecord;
952: type = m->m_type;
953: if (type == MT_OOBDATA)
954: flags |= MSG_OOB;
955: }
956: moff = 0;
957: offset = 0;
958: while (m && uio->uio_resid > 0 && error == 0) {
959: if (m->m_type == MT_OOBDATA) {
960: if (type != MT_OOBDATA)
961: break;
962: } else if (type == MT_OOBDATA)
963: break;
964: #if 0
965: /*
966: * This assertion needs rework. The trouble is Appletalk is uses many
967: * mbuf types (NOT listed in mbuf.h!) which will trigger this panic.
968: * For now just remove the assertion... CSM 9/98
969: */
970: #if DIAGNOSTIC
971: else if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
972: panic("receive 3");
973: #endif
974: #endif
975: so->so_state &= ~SS_RCVATMARK;
976: len = uio->uio_resid;
977: if (so->so_oobmark && len > so->so_oobmark - offset)
978: len = so->so_oobmark - offset;
979: if (len > m->m_len - moff)
980: len = m->m_len - moff;
981: /*
982: * If mp is set, just pass back the mbufs.
983: * Otherwise copy them out via the uio, then free.
984: * Sockbuf must be consistent here (points to current mbuf,
985: * it points to next record) when we drop priority;
986: * we must note any additions to the sockbuf when we
987: * block interrupts again.
988: */
989: if (mp == 0) {
990: splx(s);
991: error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio);
992: s = splnet();
993: } else
994: uio->uio_resid -= len;
995: if (len == m->m_len - moff) {
996: if (m->m_flags & M_EOR)
997: flags |= MSG_EOR;
998: if (flags & MSG_PEEK) {
999: m = m->m_next;
1000: moff = 0;
1001: } else {
1002: nextrecord = m->m_nextpkt;
1003: sbfree(&so->so_rcv, m);
1004: if (mp) {
1005: *mp = m;
1006: mp = &m->m_next;
1007: so->so_rcv.sb_mb = m = m->m_next;
1008: *mp = (struct mbuf *)0;
1009: } else {
1010: MFREE(m, so->so_rcv.sb_mb);
1011: m = so->so_rcv.sb_mb;
1012: }
1013: if (m)
1014: m->m_nextpkt = nextrecord;
1015: }
1016: } else {
1017: if (flags & MSG_PEEK)
1018: moff += len;
1019: else {
1020: if (mp)
1021: *mp = m_copym(m, 0, len, M_WAIT);
1022: m->m_data += len;
1023: m->m_len -= len;
1024: so->so_rcv.sb_cc -= len;
1025: }
1026: }
1027: if (so->so_oobmark) {
1028: if ((flags & MSG_PEEK) == 0) {
1029: so->so_oobmark -= len;
1030: if (so->so_oobmark == 0) {
1031: so->so_state |= SS_RCVATMARK;
1032: postevent(so, 0, EV_OOB);
1033: break;
1034: }
1035: } else {
1036: offset += len;
1037: if (offset == so->so_oobmark)
1038: break;
1039: }
1040: }
1041: if (flags & MSG_EOR)
1042: break;
1043: /*
1044: * If the MSG_WAITALL flag is set (for non-atomic socket),
1045: * we must not quit until "uio->uio_resid == 0" or an error
1046: * termination. If a signal/timeout occurs, return
1047: * with a short count but without error.
1048: * Keep sockbuf locked against other readers.
1049: */
1050: while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 &&
1051: !sosendallatonce(so) && !nextrecord) {
1052: if (so->so_error || so->so_state & SS_CANTRCVMORE)
1053: break;
1054: error = sbwait(&so->so_rcv);
1055: if (error) {
1056: sbunlock(&so->so_rcv);
1057: splx(s);
1058: KERNEL_DEBUG(DBG_FNC_SORECEIVE | DBG_FUNC_END, 0,0,0,0,0);
1059: return (0);
1060: }
1061: if (m = so->so_rcv.sb_mb)
1062: nextrecord = m->m_nextpkt;
1063: }
1064: }
1065:
1066: if (m && pr->pr_flags & PR_ATOMIC) {
1067: flags |= MSG_TRUNC;
1068: if ((flags & MSG_PEEK) == 0)
1069: (void) sbdroprecord(&so->so_rcv);
1070: }
1071: if ((flags & MSG_PEEK) == 0) {
1072: if (m == 0)
1073: so->so_rcv.sb_mb = nextrecord;
1074: if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
1075: (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
1076: (struct mbuf *)(long)flags, (struct mbuf *)0,
1077: (struct mbuf *)0);
1078: }
1079: if (orig_resid == uio->uio_resid && orig_resid &&
1080: (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) {
1081: sbunlock(&so->so_rcv);
1082: splx(s);
1083: goto restart;
1084: }
1085:
1086: if (flagsp)
1087: *flagsp |= flags;
1088: release:
1089: sbunlock(&so->so_rcv);
1090: splx(s);
1091:
1092: KERNEL_DEBUG(DBG_FNC_SORECEIVE | DBG_FUNC_END,
1093: so,
1094: uio->uio_resid,
1095: so->so_rcv.sb_cc,
1096: 0,
1097: error);
1098:
1099: return (error);
1100: }
1101:
1102: int
1103: soshutdown(so, how)
1104: register struct socket *so;
1105: register int how;
1106: {
1107: register struct protosw *pr = so->so_proto;
1108:
1109: how++;
1110: if (how & FREAD) {
1111: sorflush(so);
1112: postevent(so, 0, EV_RCLOSED);
1113: }
1114: if (how & FWRITE) {
1115: int ret = ((*pr->pr_usrreq)(so, PRU_SHUTDOWN,
1116: (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
1117: postevent(so, 0, EV_WCLOSED);
1118: return(ret);
1119: }
1120: return (0);
1121: }
1122:
1123: void
1124: sorflush(so)
1125: register struct socket *so;
1126: {
1127: register struct sockbuf *sb = &so->so_rcv;
1128: register struct protosw *pr = so->so_proto;
1129: register int s;
1130: struct sockbuf asb;
1131:
1132: sb->sb_flags |= SB_NOINTR;
1133: (void) sblock(sb, M_WAIT);
1134: s = splimp();
1135: socantrcvmore(so);
1136: sbunlock(sb);
1137: asb = *sb;
1138: bzero((caddr_t)sb, sizeof (*sb));
1139: splx(s);
1140: if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
1141: (*pr->pr_domain->dom_dispose)(asb.sb_mb);
1142: sbrelease(&asb);
1143: }
1144:
1145: int
1146: sosetopt(so, level, optname, m0)
1147: register struct socket *so;
1148: int level, optname;
1149: struct mbuf *m0;
1150: {
1151: int error = 0;
1152: register struct mbuf *m = m0;
1153:
1154: if (level != SOL_SOCKET) {
1155: if (so->so_proto && so->so_proto->pr_ctloutput)
1156: return ((*so->so_proto->pr_ctloutput)
1157: (PRCO_SETOPT, so, level, optname, &m0));
1158: error = ENOPROTOOPT;
1159: } else {
1160: switch (optname) {
1161:
1162: case SO_LINGER:
1163: if (m == NULL || m->m_len != sizeof (struct linger)) {
1164: error = EINVAL;
1165: goto bad;
1166: }
1167: so->so_linger = mtod(m, struct linger *)->l_linger;
1168: /* fall thru... */
1169:
1170: case SO_DEBUG:
1171: case SO_KEEPALIVE:
1172: case SO_DONTROUTE:
1173: case SO_USELOOPBACK:
1174: case SO_BROADCAST:
1175: case SO_REUSEADDR:
1176: case SO_REUSEPORT:
1177: case SO_OOBINLINE:
1178: case SO_RCVIF:
1179: if (m == NULL || m->m_len < sizeof (int)) {
1180: error = EINVAL;
1181: goto bad;
1182: }
1183: if (*mtod(m, int *))
1184: so->so_options |= optname;
1185: else
1186: so->so_options &= ~optname;
1187: break;
1188:
1189: case SO_SNDBUF:
1190: case SO_RCVBUF:
1191: case SO_SNDLOWAT:
1192: case SO_RCVLOWAT:
1193: if (m == NULL || m->m_len < sizeof (int)) {
1194: error = EINVAL;
1195: goto bad;
1196: }
1197: switch (optname) {
1198:
1199: case SO_SNDBUF:
1200: case SO_RCVBUF:
1201: if (sbreserve(optname == SO_SNDBUF ?
1202: &so->so_snd : &so->so_rcv,
1203: (u_long) *mtod(m, int *)) == 0) {
1204: error = ENOBUFS;
1205: goto bad;
1206: }
1207: break;
1208:
1209: case SO_SNDLOWAT:
1210: so->so_snd.sb_lowat = *mtod(m, int *);
1211: break;
1212: case SO_RCVLOWAT:
1213: so->so_rcv.sb_lowat = *mtod(m, int *);
1214: break;
1215: }
1216: break;
1217:
1218: case SO_SNDTIMEO:
1219: case SO_RCVTIMEO:
1220: {
1221: struct timeval *tv;
1222: short val;
1223:
1224: if (m == NULL || m->m_len < sizeof (*tv)) {
1225: error = EINVAL;
1226: goto bad;
1227: }
1228: tv = mtod(m, struct timeval *);
1229: #define MAX_TICKS_PER_SHORT_IN_SEC ((SHRT_MAX - hz) / hz)
1230: if (tv->tv_sec > MAX_TICKS_PER_SHORT_IN_SEC) {
1231: /* was (SHRT_MAX / hz - hz) */
1232: error = EDOM;
1233: goto bad;
1234: }
1235: val = tv->tv_sec * hz + tv->tv_usec / tick;
1236:
1237: switch (optname) {
1238:
1239: case SO_SNDTIMEO:
1240: so->so_snd.sb_timeo = val;
1241: break;
1242: case SO_RCVTIMEO:
1243: so->so_rcv.sb_timeo = val;
1244: break;
1245: }
1246: break;
1247: }
1248:
1249: default:
1250: error = ENOPROTOOPT;
1251: break;
1252: }
1253: if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) {
1254: (void) ((*so->so_proto->pr_ctloutput)
1255: (PRCO_SETOPT, so, level, optname, &m0));
1256: m = NULL; /* freed by protocol */
1257: }
1258: }
1259: bad:
1260: if (m)
1261: (void) m_free(m);
1262: return (error);
1263: }
1264:
1265: int
1266: sogetopt(so, level, optname, mp)
1267: register struct socket *so;
1268: int level, optname;
1269: struct mbuf **mp;
1270: {
1271: register struct mbuf *m;
1272:
1273: if (level != SOL_SOCKET) {
1274: if (so->so_proto && so->so_proto->pr_ctloutput) {
1275: return ((*so->so_proto->pr_ctloutput)
1276: (PRCO_GETOPT, so, level, optname, mp));
1277: } else
1278: return (ENOPROTOOPT);
1279: } else {
1280: m = m_get(M_WAIT, MT_SOOPTS);
1281: m->m_len = sizeof (int);
1282:
1283: switch (optname) {
1284:
1285: case SO_LINGER:
1286: m->m_len = sizeof (struct linger);
1287: mtod(m, struct linger *)->l_onoff =
1288: so->so_options & SO_LINGER;
1289: mtod(m, struct linger *)->l_linger = so->so_linger;
1290: break;
1291:
1292: case SO_USELOOPBACK:
1293: case SO_DONTROUTE:
1294: case SO_DEBUG:
1295: case SO_KEEPALIVE:
1296: case SO_REUSEADDR:
1297: case SO_REUSEPORT:
1298: case SO_BROADCAST:
1299: case SO_OOBINLINE:
1300: *mtod(m, int *) = so->so_options & optname;
1301: break;
1302:
1303: case SO_TYPE:
1304: *mtod(m, int *) = so->so_type;
1305: break;
1306:
1307: case SO_ERROR:
1308: *mtod(m, int *) = so->so_error;
1309: so->so_error = 0;
1310: break;
1311:
1312: case SO_SNDBUF:
1313: *mtod(m, int *) = so->so_snd.sb_hiwat;
1314: break;
1315:
1316: case SO_RCVBUF:
1317: *mtod(m, int *) = so->so_rcv.sb_hiwat;
1318: break;
1319:
1320: case SO_SNDLOWAT:
1321: *mtod(m, int *) = so->so_snd.sb_lowat;
1322: break;
1323:
1324: case SO_RCVLOWAT:
1325: *mtod(m, int *) = so->so_rcv.sb_lowat;
1326: break;
1327:
1328: case SO_SNDTIMEO:
1329: case SO_RCVTIMEO:
1330: {
1331: int val = (optname == SO_SNDTIMEO ?
1332: so->so_snd.sb_timeo : so->so_rcv.sb_timeo);
1333:
1334: m->m_len = sizeof(struct timeval);
1335: mtod(m, struct timeval *)->tv_sec = val / hz;
1336: mtod(m, struct timeval *)->tv_usec =
1337: (val % hz) / tick;
1338: break;
1339: }
1340:
1341: default:
1342: (void)m_free(m);
1343: return (ENOPROTOOPT);
1344: }
1345: *mp = m;
1346: return (0);
1347: }
1348: }
1349:
1350: void
1351: sohasoutofband(so)
1352: register struct socket *so;
1353: {
1354: struct proc *p;
1355:
1356: if (so->so_pgid < 0)
1357: gsignal(-so->so_pgid, SIGURG);
1358: else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0)
1359: psignal(p, SIGURG);
1360: selwakeup(&so->so_rcv.sb_sel);
1361: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.