|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution is only permitted until one year after the first shipment
6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
7: * binary forms are permitted provided that: (1) source distributions retain
8: * this entire copyright notice and comment, and (2) distributions including
9: * binaries display the following acknowledgement: This product includes
10: * software developed by the University of California, Berkeley and its
11: * contributors'' in the documentation or other materials provided with the
12: * distribution and in all advertising materials mentioning features or use
13: * of this software. Neither the name of the University nor the names of
14: * its contributors may be used to endorse or promote products derived from
15: * this software without specific prior written permission.
16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19: *
20: * @(#)uipc_socket.c 7.23 (Berkeley) 6/29/90
21: */
22:
23: #include "param.h"
24: #include "user.h"
25: #include "proc.h"
26: #include "file.h"
27: #include "malloc.h"
28: #include "mbuf.h"
29: #include "domain.h"
30: #include "kernel.h"
31: #include "protosw.h"
32: #include "socket.h"
33: #include "socketvar.h"
34: #include "time.h"
35:
36: /*
37: * Socket operation routines.
38: * These routines are called by the routines in
39: * sys_socket.c or from a system process, and
40: * implement the semantics of socket operations by
41: * switching out to the protocol specific routines.
42: *
43: * TODO:
44: * test socketpair
45: * clean up async
46: * out-of-band is a kludge
47: */
48: /*ARGSUSED*/
49: socreate(dom, aso, type, proto)
50: struct socket **aso;
51: register int type;
52: int proto;
53: {
54: register struct protosw *prp;
55: register struct socket *so;
56: register int error;
57:
58: if (proto)
59: prp = pffindproto(dom, proto, type);
60: else
61: prp = pffindtype(dom, type);
62: if (prp == 0)
63: return (EPROTONOSUPPORT);
64: if (prp->pr_type != type)
65: return (EPROTOTYPE);
66: MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT);
67: bzero((caddr_t)so, sizeof(*so));
68: so->so_type = type;
69: if (u.u_uid == 0)
70: so->so_state = SS_PRIV;
71: so->so_proto = prp;
72: error =
73: (*prp->pr_usrreq)(so, PRU_ATTACH,
74: (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0);
75: if (error) {
76: so->so_state |= SS_NOFDREF;
77: sofree(so);
78: return (error);
79: }
80: *aso = so;
81: return (0);
82: }
83:
84: sobind(so, nam)
85: struct socket *so;
86: struct mbuf *nam;
87: {
88: int s = splnet();
89: int error;
90:
91: error =
92: (*so->so_proto->pr_usrreq)(so, PRU_BIND,
93: (struct mbuf *)0, nam, (struct mbuf *)0);
94: splx(s);
95: return (error);
96: }
97:
98: solisten(so, backlog)
99: register struct socket *so;
100: int backlog;
101: {
102: int s = splnet(), error;
103:
104: error =
105: (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
106: (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
107: if (error) {
108: splx(s);
109: return (error);
110: }
111: if (so->so_q == 0)
112: so->so_options |= SO_ACCEPTCONN;
113: if (backlog < 0)
114: backlog = 0;
115: so->so_qlimit = min(backlog, SOMAXCONN);
116: splx(s);
117: return (0);
118: }
119:
120: sofree(so)
121: register struct socket *so;
122: {
123:
124: if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
125: return;
126: if (so->so_head) {
127: if (!soqremque(so, 0) && !soqremque(so, 1))
128: panic("sofree dq");
129: so->so_head = 0;
130: }
131: sbrelease(&so->so_snd);
132: sorflush(so);
133: FREE(so, M_SOCKET);
134: }
135:
136: /*
137: * Close a socket on last file table reference removal.
138: * Initiate disconnect if connected.
139: * Free socket when disconnect complete.
140: */
141: soclose(so)
142: register struct socket *so;
143: {
144: int s = splnet(); /* conservative */
145: int error = 0;
146:
147: if (so->so_options & SO_ACCEPTCONN) {
148: while (so->so_q0)
149: (void) soabort(so->so_q0);
150: while (so->so_q)
151: (void) soabort(so->so_q);
152: }
153: if (so->so_pcb == 0)
154: goto discard;
155: if (so->so_state & SS_ISCONNECTED) {
156: if ((so->so_state & SS_ISDISCONNECTING) == 0) {
157: error = sodisconnect(so);
158: if (error)
159: goto drop;
160: }
161: if (so->so_options & SO_LINGER) {
162: if ((so->so_state & SS_ISDISCONNECTING) &&
163: (so->so_state & SS_NBIO))
164: goto drop;
165: while (so->so_state & SS_ISCONNECTED)
166: if (error = tsleep((caddr_t)&so->so_timeo,
167: PSOCK | PCATCH, netcls, so->so_linger))
168: break;
169: }
170: }
171: drop:
172: if (so->so_pcb) {
173: int error2 =
174: (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
175: (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
176: if (error == 0)
177: error = error2;
178: }
179: discard:
180: if (so->so_state & SS_NOFDREF)
181: panic("soclose: NOFDREF");
182: so->so_state |= SS_NOFDREF;
183: sofree(so);
184: splx(s);
185: return (error);
186: }
187:
188: /*
189: * Must be called at splnet...
190: */
191: soabort(so)
192: struct socket *so;
193: {
194:
195: return (
196: (*so->so_proto->pr_usrreq)(so, PRU_ABORT,
197: (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
198: }
199:
200: soaccept(so, nam)
201: register struct socket *so;
202: struct mbuf *nam;
203: {
204: int s = splnet();
205: int error;
206:
207: if ((so->so_state & SS_NOFDREF) == 0)
208: panic("soaccept: !NOFDREF");
209: so->so_state &= ~SS_NOFDREF;
210: error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
211: (struct mbuf *)0, nam, (struct mbuf *)0);
212: splx(s);
213: return (error);
214: }
215:
216: soconnect(so, nam)
217: register struct socket *so;
218: struct mbuf *nam;
219: {
220: int s;
221: int error;
222:
223: if (so->so_options & SO_ACCEPTCONN)
224: return (EOPNOTSUPP);
225: s = splnet();
226: /*
227: * If protocol is connection-based, can only connect once.
228: * Otherwise, if connected, try to disconnect first.
229: * This allows user to disconnect by connecting to, e.g.,
230: * a null address.
231: */
232: if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
233: ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
234: (error = sodisconnect(so))))
235: error = EISCONN;
236: else
237: error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
238: (struct mbuf *)0, nam, (struct mbuf *)0);
239: splx(s);
240: return (error);
241: }
242:
243: soconnect2(so1, so2)
244: register struct socket *so1;
245: struct socket *so2;
246: {
247: int s = splnet();
248: int error;
249:
250: error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2,
251: (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0);
252: splx(s);
253: return (error);
254: }
255:
256: sodisconnect(so)
257: register struct socket *so;
258: {
259: int s = splnet();
260: int error;
261:
262: if ((so->so_state & SS_ISCONNECTED) == 0) {
263: error = ENOTCONN;
264: goto bad;
265: }
266: if (so->so_state & SS_ISDISCONNECTING) {
267: error = EALREADY;
268: goto bad;
269: }
270: error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
271: (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
272: bad:
273: splx(s);
274: return (error);
275: }
276:
277: /*
278: * Send on a socket.
279: * If send must go all at once and message is larger than
280: * send buffering, then hard error.
281: * Lock against other senders.
282: * If must go all at once and not enough room now, then
283: * inform user that this would block and do nothing.
284: * Otherwise, if nonblocking, send as much as possible.
285: * The data to be sent is described by "uio" if nonzero,
286: * otherwise by the mbuf chain "top" (which must be null
287: * if uio is not). Data provided in mbuf chain must be small
288: * enough to send all at once.
289: *
290: * Returns nonzero on error, timeout or signal; callers
291: * must check for short counts if EINTR/ERESTART are returned.
292: * Data and control buffers are freed on return.
293: */
294: sosend(so, addr, uio, top, control, flags)
295: register struct socket *so;
296: struct mbuf *addr;
297: struct uio *uio;
298: struct mbuf *top;
299: struct mbuf *control;
300: int flags;
301: {
302: struct mbuf **mp;
303: register struct mbuf *m;
304: register long space, len, resid;
305: int clen = 0, error, s, dontroute, mlen;
306: int atomic = sosendallatonce(so) || top;
307:
308: if (uio)
309: resid = uio->uio_resid;
310: else
311: resid = top->m_pkthdr.len;
312: dontroute =
313: (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
314: (so->so_proto->pr_flags & PR_ATOMIC);
315: u.u_ru.ru_msgsnd++;
316: if (control)
317: clen = control->m_len;
318: #define snderr(errno) { error = errno; splx(s); goto release; }
319:
320: restart:
321: if (error = sblock(&so->so_snd))
322: goto out;
323: do {
324: s = splnet();
325: if (so->so_state & SS_CANTSENDMORE)
326: snderr(EPIPE);
327: if (so->so_error)
328: snderr(so->so_error);
329: if ((so->so_state & SS_ISCONNECTED) == 0) {
330: if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
331: if ((so->so_state & SS_ISCONFIRMING) == 0)
332: snderr(ENOTCONN);
333: } else if (addr == 0)
334: snderr(EDESTADDRREQ);
335: }
336: space = sbspace(&so->so_snd);
337: if (flags & MSG_OOB)
338: space += 1024;
339: if (space < resid + clen &&
340: (atomic || space < so->so_snd.sb_lowat || space < clen)) {
341: if (atomic && resid > so->so_snd.sb_hiwat ||
342: clen > so->so_snd.sb_hiwat)
343: snderr(EMSGSIZE);
344: if (so->so_state & SS_NBIO)
345: snderr(EWOULDBLOCK);
346: sbunlock(&so->so_snd);
347: error = sbwait(&so->so_snd);
348: splx(s);
349: if (error)
350: goto out;
351: goto restart;
352: }
353: splx(s);
354: mp = ⊤
355: space -= clen;
356: do {
357: if (uio == NULL) {
358: /*
359: * Data is prepackaged in "top".
360: */
361: resid = 0;
362: if (flags & MSG_EOR)
363: top->m_flags |= M_EOR;
364: } else do {
365: if (top == 0) {
366: MGETHDR(m, M_WAIT, MT_DATA);
367: mlen = MHLEN;
368: m->m_pkthdr.len = 0;
369: m->m_pkthdr.rcvif = (struct ifnet *)0;
370: } else {
371: MGET(m, M_WAIT, MT_DATA);
372: mlen = MLEN;
373: }
374: if (resid >= MINCLSIZE && space >= MCLBYTES) {
375: MCLGET(m, M_WAIT);
376: if ((m->m_flags & M_EXT) == 0)
377: goto nopages;
378: mlen = MCLBYTES;
379: #ifdef MAPPED_MBUFS
380: len = min(MCLBYTES, resid);
381: #else
382: if (top == 0) {
383: len = min(MCLBYTES - max_hdr, resid);
384: m->m_data += max_hdr;
385: }
386: #endif
387: space -= MCLBYTES;
388: } else {
389: nopages:
390: len = min(min(mlen, resid), space);
391: space -= len;
392: /*
393: * For datagram protocols, leave room
394: * for protocol headers in first mbuf.
395: */
396: if (atomic && top == 0 && len < mlen)
397: MH_ALIGN(m, len);
398: }
399: error = uiomove(mtod(m, caddr_t), len, uio);
400: resid = uio->uio_resid;
401: m->m_len = len;
402: *mp = m;
403: top->m_pkthdr.len += len;
404: if (error)
405: goto release;
406: mp = &m->m_next;
407: if (resid <= 0) {
408: if (flags & MSG_EOR)
409: top->m_flags |= M_EOR;
410: break;
411: }
412: } while (space > 0 && atomic);
413: if (dontroute)
414: so->so_options |= SO_DONTROUTE;
415: s = splnet(); /* XXX */
416: error = (*so->so_proto->pr_usrreq)(so,
417: (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
418: top, addr, control);
419: splx(s);
420: if (dontroute)
421: so->so_options &= ~SO_DONTROUTE;
422: clen = 0;
423: control = 0;
424: top = 0;
425: mp = ⊤
426: if (error)
427: goto release;
428: } while (resid && space > 0);
429: } while (resid);
430:
431: release:
432: sbunlock(&so->so_snd);
433: out:
434: if (top)
435: m_freem(top);
436: if (control)
437: m_freem(control);
438: return (error);
439: }
440:
441: /*
442: * Implement receive operations on a socket.
443: * We depend on the way that records are added to the sockbuf
444: * by sbappend*. In particular, each record (mbufs linked through m_next)
445: * must begin with an address if the protocol so specifies,
446: * followed by an optional mbuf or mbufs containing ancillary data,
447: * and then zero or more mbufs of data.
448: * In order to avoid blocking network interrupts for the entire time here,
449: * we splx() while doing the actual copy to user space.
450: * Although the sockbuf is locked, new data may still be appended,
451: * and thus we must maintain consistency of the sockbuf during that time.
452: *
453: * The caller may receive the data as a single mbuf chain by supplying
454: * an mbuf **mp0 for use in returning the chain. The uio is then used
455: * only for the count in uio_resid.
456: */
457: soreceive(so, paddr, uio, mp0, controlp, flagsp)
458: register struct socket *so;
459: struct mbuf **paddr;
460: struct uio *uio;
461: struct mbuf **mp0;
462: struct mbuf **controlp;
463: int *flagsp;
464: {
465: register struct mbuf *m, **mp;
466: register int flags, len, error, s, offset;
467: struct protosw *pr = so->so_proto;
468: struct mbuf *nextrecord;
469: int moff, type;
470:
471: mp = mp0;
472: if (paddr)
473: *paddr = 0;
474: if (controlp)
475: *controlp = 0;
476: if (flagsp)
477: flags = *flagsp &~ MSG_EOR;
478: else
479: flags = 0;
480: if (flags & MSG_OOB) {
481: m = m_get(M_WAIT, MT_DATA);
482: error = (*pr->pr_usrreq)(so, PRU_RCVOOB,
483: m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0);
484: if (error)
485: goto bad;
486: do {
487: error = uiomove(mtod(m, caddr_t),
488: (int) min(uio->uio_resid, m->m_len), uio);
489: m = m_free(m);
490: } while (uio->uio_resid && error == 0 && m);
491: bad:
492: if (m)
493: m_freem(m);
494: return (error);
495: }
496: if (mp)
497: *mp = (struct mbuf *)0;
498: if (so->so_state & SS_ISCONFIRMING && uio->uio_resid)
499: (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
500: (struct mbuf *)0, (struct mbuf *)0);
501:
502: restart:
503: if (error = sblock(&so->so_rcv))
504: return (error);
505: s = splnet();
506:
507: m = so->so_rcv.sb_mb;
508: /*
509: * If we have less data than requested, block awaiting more
510: * (subject to any timeout) if:
511: * 1. the current count is less than the low water mark, or
512: * 2. MSG_WAITALL is set, and it is possible to do the entire
513: * receive operation at once if we block (resid <= hiwat).
514: * If MSG_WAITALL is set but resid is larger than the receive buffer,
515: * we have to do the receive in sections, and thus risk returning
516: * a short count if a timeout or signal occurs after we start.
517: */
518: if (m == 0 || so->so_rcv.sb_cc < uio->uio_resid &&
519: (so->so_rcv.sb_cc < so->so_rcv.sb_lowat ||
520: ((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat))) {
521: #ifdef DIAGNOSTIC
522: if (m == 0 && so->so_rcv.sb_cc)
523: panic("receive 1");
524: #endif
525: if (so->so_error) {
526: error = so->so_error;
527: so->so_error = 0;
528: goto release;
529: }
530: if (so->so_state & SS_CANTRCVMORE)
531: goto release;
532: if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 &&
533: (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
534: error = ENOTCONN;
535: goto release;
536: }
537: if (uio->uio_resid == 0)
538: goto release;
539: if (so->so_state & SS_NBIO) {
540: error = EWOULDBLOCK;
541: goto release;
542: }
543: sbunlock(&so->so_rcv);
544: error = sbwait(&so->so_rcv);
545: splx(s);
546: if (error)
547: return (error);
548: goto restart;
549: }
550: u.u_ru.ru_msgrcv++;
551: nextrecord = m->m_nextpkt;
552: if (pr->pr_flags & PR_ADDR) {
553: #ifdef DIAGNOSTIC
554: if (m->m_type != MT_SONAME)
555: panic("receive 1a");
556: #endif
557: if (flags & MSG_PEEK) {
558: if (paddr)
559: *paddr = m_copy(m, 0, m->m_len);
560: m = m->m_next;
561: } else {
562: sbfree(&so->so_rcv, m);
563: if (paddr) {
564: *paddr = m;
565: so->so_rcv.sb_mb = m->m_next;
566: m->m_next = 0;
567: m = so->so_rcv.sb_mb;
568: } else {
569: MFREE(m, so->so_rcv.sb_mb);
570: m = so->so_rcv.sb_mb;
571: }
572: }
573: }
574: while (m && m->m_type == MT_CONTROL && error == 0) {
575: if (flags & MSG_PEEK) {
576: if (controlp)
577: *controlp = m_copy(m, 0, m->m_len);
578: m = m->m_next;
579: } else {
580: sbfree(&so->so_rcv, m);
581: if (controlp) {
582: if (pr->pr_domain->dom_externalize &&
583: mtod(m, struct cmsghdr *)->cmsg_type ==
584: SCM_RIGHTS)
585: error = (*pr->pr_domain->dom_externalize)(m);
586: *controlp = m;
587: so->so_rcv.sb_mb = m->m_next;
588: m->m_next = 0;
589: m = so->so_rcv.sb_mb;
590: } else {
591: MFREE(m, so->so_rcv.sb_mb);
592: m = so->so_rcv.sb_mb;
593: }
594: }
595: if (controlp)
596: controlp = &(*controlp)->m_next;
597: }
598: if (m) {
599: if ((flags & MSG_PEEK) == 0)
600: m->m_nextpkt = nextrecord;
601: type = m->m_type;
602: }
603: moff = 0;
604: offset = 0;
605: while (m && m->m_type == type && uio->uio_resid > 0 && error == 0) {
606: if (m->m_type == MT_OOBDATA)
607: flags |= MSG_OOB;
608: #ifdef DIAGNOSTIC
609: else if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
610: panic("receive 3");
611: #endif
612: type = m->m_type;
613: so->so_state &= ~SS_RCVATMARK;
614: len = uio->uio_resid;
615: if (so->so_oobmark && len > so->so_oobmark - offset)
616: len = so->so_oobmark - offset;
617: if (len > m->m_len - moff)
618: len = m->m_len - moff;
619: /*
620: * If mp is set, just pass back the mbufs.
621: * Otherwise copy them out via the uio, then free.
622: * Sockbuf must be consistent here (points to current mbuf,
623: * it points to next record) when we drop priority;
624: * we must note any additions to the sockbuf when we
625: * block interrupts again.
626: */
627: if (mp == 0) {
628: splx(s);
629: error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio);
630: s = splnet();
631: } else
632: uio->uio_resid -= len;
633: if (len == m->m_len - moff) {
634: if (m->m_flags & M_EOR)
635: flags |= MSG_EOR;
636: if (flags & MSG_PEEK) {
637: m = m->m_next;
638: moff = 0;
639: } else {
640: nextrecord = m->m_nextpkt;
641: sbfree(&so->so_rcv, m);
642: if (mp) {
643: *mp = m;
644: mp = &m->m_next;
645: so->so_rcv.sb_mb = m = m->m_next;
646: *mp = (struct mbuf *)0;
647: } else {
648: MFREE(m, so->so_rcv.sb_mb);
649: m = so->so_rcv.sb_mb;
650: }
651: if (m)
652: m->m_nextpkt = nextrecord;
653: }
654: } else {
655: if (flags & MSG_PEEK)
656: moff += len;
657: else {
658: if (mp)
659: *mp = m_copym(m, 0, len, M_WAIT);
660: m->m_data += len;
661: m->m_len -= len;
662: so->so_rcv.sb_cc -= len;
663: }
664: }
665: if (so->so_oobmark) {
666: if ((flags & MSG_PEEK) == 0) {
667: so->so_oobmark -= len;
668: if (so->so_oobmark == 0) {
669: so->so_state |= SS_RCVATMARK;
670: break;
671: }
672: } else
673: offset += len;
674: }
675: if (flags & MSG_EOR)
676: break;
677: /*
678: * If the MSG_WAITALL flag is set (for non-atomic socket),
679: * we must not quit until "uio->uio_resid == 0" or an error
680: * termination. If a signal/timeout occurs, return
681: * with a short count but without error.
682: * Keep sockbuf locked against other readers.
683: */
684: while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 &&
685: !sosendallatonce(so)) {
686: error = sbwait(&so->so_rcv);
687: if (error) {
688: sbunlock(&so->so_rcv);
689: splx(s);
690: return (0);
691: }
692: if (m = so->so_rcv.sb_mb)
693: nextrecord = m->m_nextpkt;
694: if (so->so_error || so->so_state & SS_CANTRCVMORE)
695: break;
696: continue;
697: }
698: }
699: if ((flags & MSG_PEEK) == 0) {
700: if (m == 0)
701: so->so_rcv.sb_mb = nextrecord;
702: else if (pr->pr_flags & PR_ATOMIC) {
703: flags |= MSG_TRUNC;
704: (void) sbdroprecord(&so->so_rcv);
705: }
706: if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
707: (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
708: (struct mbuf *)flags, (struct mbuf *)0,
709: (struct mbuf *)0);
710: }
711: if (flagsp)
712: *flagsp |= flags;
713: release:
714: sbunlock(&so->so_rcv);
715: splx(s);
716: return (error);
717: }
718:
719: soshutdown(so, how)
720: register struct socket *so;
721: register int how;
722: {
723: register struct protosw *pr = so->so_proto;
724:
725: how++;
726: if (how & FREAD)
727: sorflush(so);
728: if (how & FWRITE)
729: return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN,
730: (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
731: return (0);
732: }
733:
734: sorflush(so)
735: register struct socket *so;
736: {
737: register struct sockbuf *sb = &so->so_rcv;
738: register struct protosw *pr = so->so_proto;
739: register int s;
740: struct sockbuf asb;
741:
742: sb->sb_flags |= SB_NOINTR;
743: (void) sblock(sb);
744: s = splimp();
745: socantrcvmore(so);
746: sbunlock(sb);
747: asb = *sb;
748: bzero((caddr_t)sb, sizeof (*sb));
749: splx(s);
750: if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
751: (*pr->pr_domain->dom_dispose)(asb.sb_mb);
752: sbrelease(&asb);
753: }
754:
755: sosetopt(so, level, optname, m0)
756: register struct socket *so;
757: int level, optname;
758: struct mbuf *m0;
759: {
760: int error = 0;
761: register struct mbuf *m = m0;
762:
763: if (level != SOL_SOCKET) {
764: if (so->so_proto && so->so_proto->pr_ctloutput)
765: return ((*so->so_proto->pr_ctloutput)
766: (PRCO_SETOPT, so, level, optname, &m0));
767: error = ENOPROTOOPT;
768: } else {
769: switch (optname) {
770:
771: case SO_LINGER:
772: if (m == NULL || m->m_len != sizeof (struct linger)) {
773: error = EINVAL;
774: goto bad;
775: }
776: so->so_linger = mtod(m, struct linger *)->l_linger;
777: /* fall thru... */
778:
779: case SO_DEBUG:
780: case SO_KEEPALIVE:
781: case SO_DONTROUTE:
782: case SO_USELOOPBACK:
783: case SO_BROADCAST:
784: case SO_REUSEADDR:
785: case SO_OOBINLINE:
786: if (m == NULL || m->m_len < sizeof (int)) {
787: error = EINVAL;
788: goto bad;
789: }
790: if (*mtod(m, int *))
791: so->so_options |= optname;
792: else
793: so->so_options &= ~optname;
794: break;
795:
796: case SO_SNDBUF:
797: case SO_RCVBUF:
798: case SO_SNDLOWAT:
799: case SO_RCVLOWAT:
800: if (m == NULL || m->m_len < sizeof (int)) {
801: error = EINVAL;
802: goto bad;
803: }
804: switch (optname) {
805:
806: case SO_SNDBUF:
807: case SO_RCVBUF:
808: if (sbreserve(optname == SO_SNDBUF ?
809: &so->so_snd : &so->so_rcv,
810: (u_long) *mtod(m, int *)) == 0) {
811: error = ENOBUFS;
812: goto bad;
813: }
814: break;
815:
816: case SO_SNDLOWAT:
817: so->so_snd.sb_lowat = *mtod(m, int *);
818: break;
819: case SO_RCVLOWAT:
820: so->so_rcv.sb_lowat = *mtod(m, int *);
821: break;
822: }
823: break;
824:
825: case SO_SNDTIMEO:
826: case SO_RCVTIMEO:
827: {
828: struct timeval *tv;
829: short val;
830:
831: if (m == NULL || m->m_len < sizeof (*tv)) {
832: error = EINVAL;
833: goto bad;
834: }
835: tv = mtod(m, struct timeval *);
836: if (tv->tv_sec > SHRT_MAX / hz - hz) {
837: error = EDOM;
838: goto bad;
839: }
840: val = tv->tv_sec * hz + tv->tv_usec / tick;
841:
842: switch (optname) {
843:
844: case SO_SNDTIMEO:
845: so->so_snd.sb_timeo = val;
846: break;
847: case SO_RCVTIMEO:
848: so->so_rcv.sb_timeo = val;
849: break;
850: }
851: break;
852: }
853:
854: default:
855: error = ENOPROTOOPT;
856: break;
857: }
858: }
859: bad:
860: if (m)
861: (void) m_free(m);
862: return (error);
863: }
864:
865: sogetopt(so, level, optname, mp)
866: register struct socket *so;
867: int level, optname;
868: struct mbuf **mp;
869: {
870: register struct mbuf *m;
871:
872: if (level != SOL_SOCKET) {
873: if (so->so_proto && so->so_proto->pr_ctloutput) {
874: return ((*so->so_proto->pr_ctloutput)
875: (PRCO_GETOPT, so, level, optname, mp));
876: } else
877: return (ENOPROTOOPT);
878: } else {
879: m = m_get(M_WAIT, MT_SOOPTS);
880: m->m_len = sizeof (int);
881:
882: switch (optname) {
883:
884: case SO_LINGER:
885: m->m_len = sizeof (struct linger);
886: mtod(m, struct linger *)->l_onoff =
887: so->so_options & SO_LINGER;
888: mtod(m, struct linger *)->l_linger = so->so_linger;
889: break;
890:
891: case SO_USELOOPBACK:
892: case SO_DONTROUTE:
893: case SO_DEBUG:
894: case SO_KEEPALIVE:
895: case SO_REUSEADDR:
896: case SO_BROADCAST:
897: case SO_OOBINLINE:
898: *mtod(m, int *) = so->so_options & optname;
899: break;
900:
901: case SO_TYPE:
902: *mtod(m, int *) = so->so_type;
903: break;
904:
905: case SO_ERROR:
906: *mtod(m, int *) = so->so_error;
907: so->so_error = 0;
908: break;
909:
910: case SO_SNDBUF:
911: *mtod(m, int *) = so->so_snd.sb_hiwat;
912: break;
913:
914: case SO_RCVBUF:
915: *mtod(m, int *) = so->so_rcv.sb_hiwat;
916: break;
917:
918: case SO_SNDLOWAT:
919: *mtod(m, int *) = so->so_snd.sb_lowat;
920: break;
921:
922: case SO_RCVLOWAT:
923: *mtod(m, int *) = so->so_rcv.sb_lowat;
924: break;
925:
926: case SO_SNDTIMEO:
927: case SO_RCVTIMEO:
928: {
929: int val = (optname == SO_SNDTIMEO ?
930: so->so_snd.sb_timeo : so->so_rcv.sb_timeo);
931:
932: m->m_len = sizeof(struct timeval);
933: mtod(m, struct timeval *)->tv_sec = val / hz;
934: mtod(m, struct timeval *)->tv_usec =
935: (val % hz) / tick;
936: break;
937: }
938:
939: default:
940: (void)m_free(m);
941: return (ENOPROTOOPT);
942: }
943: *mp = m;
944: return (0);
945: }
946: }
947:
948: sohasoutofband(so)
949: register struct socket *so;
950: {
951: struct proc *p;
952:
953: if (so->so_pgid < 0)
954: gsignal(-so->so_pgid, SIGURG);
955: else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0)
956: psignal(p, SIGURG);
957: if (so->so_rcv.sb_sel) {
958: selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL);
959: so->so_rcv.sb_sel = 0;
960: so->so_rcv.sb_flags &= ~SB_COLL;
961: }
962: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.