|
|
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_socket2.c 8.2 (Berkeley) 2/14/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/buf.h> ! 66: #include <sys/malloc.h> ! 67: #include <sys/mbuf.h> ! 68: #include <sys/protosw.h> ! 69: #include <sys/socket.h> ! 70: #include <sys/socketvar.h> ! 71: #include <sys/ev.h> ! 72: ! 73: /* ! 74: * Primitive routines for operating on sockets and socket buffers ! 75: */ ! 76: ! 77: /* strings for sleep message: */ ! 78: char netio[] = "netio"; ! 79: char netcon[] = "netcon"; ! 80: char netcls[] = "netcls"; ! 81: ! 82: u_long sb_max = SB_MAX; /* patchable */ ! 83: ! 84: /* ! 85: * Procedures to manipulate state flags of socket ! 86: * and do appropriate wakeups. Normal sequence from the ! 87: * active (originating) side is that soisconnecting() is ! 88: * called during processing of connect() call, ! 89: * resulting in an eventual call to soisconnected() if/when the ! 90: * connection is established. When the connection is torn down ! 91: * soisdisconnecting() is called during processing of disconnect() call, ! 92: * and soisdisconnected() is called when the connection to the peer ! 93: * is totally severed. The semantics of these routines are such that ! 94: * connectionless protocols can call soisconnected() and soisdisconnected() ! 95: * only, bypassing the in-progress calls when setting up a ``connection'' ! 96: * takes no time. ! 97: * ! 98: * From the passive side, a socket is created with ! 99: * two queues of sockets: so_q0 for connections in progress ! 100: * and so_q for connections already made and awaiting user acceptance. ! 101: * As a protocol is preparing incoming connections, it creates a socket ! 102: * structure queued on so_q0 by calling sonewconn(). When the connection ! 103: * is established, soisconnected() is called, and transfers the ! 104: * socket structure to so_q, making it available to accept(). ! 105: * ! 106: * If a socket is closed with sockets on either ! 107: * so_q0 or so_q, these sockets are dropped. ! 108: * ! 109: * If higher level protocols are implemented in ! 110: * the kernel, the wakeups done here will sometimes ! 111: * cause software-interrupt process scheduling. ! 112: */ ! 113: ! 114: void ! 115: soisconnecting(so) ! 116: register struct socket *so; ! 117: { ! 118: ! 119: so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING); ! 120: so->so_state |= SS_ISCONNECTING; ! 121: } ! 122: ! 123: void ! 124: soisconnected(so) ! 125: register struct socket *so; ! 126: { ! 127: register struct socket *head = so->so_head; ! 128: ! 129: so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING); ! 130: so->so_state |= SS_ISCONNECTED; ! 131: if (head && soqremque(so, 0)) { ! 132: postevent(head,0,EV_RCONN); ! 133: soqinsque(head, so, 1); ! 134: sorwakeup(head); ! 135: wakeup((caddr_t)&head->so_timeo); ! 136: } else { ! 137: postevent(so,0,EV_WCONN); ! 138: wakeup((caddr_t)&so->so_timeo); ! 139: sorwakeup(so); ! 140: sowwakeup(so); ! 141: } ! 142: } ! 143: ! 144: void ! 145: soisdisconnecting(so) ! 146: register struct socket *so; ! 147: { ! 148: ! 149: so->so_state &= ~SS_ISCONNECTING; ! 150: so->so_state |= (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE); ! 151: wakeup((caddr_t)&so->so_timeo); ! 152: sowwakeup(so); ! 153: sorwakeup(so); ! 154: } ! 155: ! 156: void ! 157: soisdisconnected(so) ! 158: register struct socket *so; ! 159: { ! 160: ! 161: so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); ! 162: so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE); ! 163: wakeup((caddr_t)&so->so_timeo); ! 164: sowwakeup(so); ! 165: sorwakeup(so); ! 166: } ! 167: ! 168: /* ! 169: * When an attempt at a new connection is noted on a socket ! 170: * which accepts connections, sonewconn is called. If the ! 171: * connection is possible (subject to space constraints, etc.) ! 172: * then we allocate a new structure, propoerly linked into the ! 173: * data structure of the original socket, and return this. ! 174: * Connstatus may be 0, or SO_ISCONFIRMING, or SO_ISCONNECTED. ! 175: * ! 176: * Currently, sonewconn() is defined as sonewconn1() in socketvar.h ! 177: * to catch calls that are missing the (new) second parameter. ! 178: */ ! 179: struct socket * ! 180: sonewconn1(head, connstatus) ! 181: register struct socket *head; ! 182: int connstatus; ! 183: { ! 184: register struct socket *so; ! 185: int soqueue = connstatus ? 1 : 0; ! 186: ! 187: if (head->so_qlen + head->so_q0len > 3 * head->so_qlimit / 2) ! 188: return ((struct socket *)0); ! 189: ! 190: #ifdef SOCKET_CACHE_ON ! 191: cached_sock_alloc(&so); ! 192: #else ! 193: MALLOC_ZONE(so, struct socket *, sizeof(*so), M_SOCKET, M_WAITOK); ! 194: bzero((caddr_t)so, sizeof(*so)); ! 195: #endif ! 196: ! 197: if (so == NULL) ! 198: return ((struct socket *)0); ! 199: so->so_type = head->so_type; ! 200: so->so_options = head->so_options &~ SO_ACCEPTCONN; ! 201: so->so_linger = head->so_linger; ! 202: so->so_state = head->so_state | SS_NOFDREF; ! 203: so->so_proto = head->so_proto; ! 204: so->so_timeo = head->so_timeo; ! 205: so->so_pgid = head->so_pgid; ! 206: (void) soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat); ! 207: soqinsque(head, so, soqueue); ! 208: if ((*so->so_proto->pr_usrreq)(so, PRU_ATTACH, ! 209: (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)) { ! 210: (void) soqremque(so, soqueue); ! 211: ! 212: #ifdef SOCKET_CACHE_ON ! 213: cached_sock_free(so); ! 214: #else ! 215: (void) _FREE_ZONE((caddr_t)so, sizeof *so, M_SOCKET); ! 216: #endif ! 217: return ((struct socket *)0); ! 218: } ! 219: if (connstatus) { ! 220: sorwakeup(head); ! 221: wakeup((caddr_t)&head->so_timeo); ! 222: so->so_state |= connstatus; ! 223: } ! 224: so->so_rcv.sb_flags |= SB_RECV; ! 225: so->so_rcv.sb_so = so->so_snd.sb_so = so; ! 226: TAILQ_INIT(&so->so_evlist); ! 227: return (so); ! 228: } ! 229: ! 230: void ! 231: soqinsque(head, so, q) ! 232: register struct socket *head, *so; ! 233: int q; ! 234: { ! 235: ! 236: register struct socket **prev; ! 237: so->so_head = head; ! 238: if (q == 0) { ! 239: head->so_q0len++; ! 240: so->so_q0 = 0; ! 241: for (prev = &(head->so_q0); *prev; ) ! 242: prev = &((*prev)->so_q0); ! 243: } else { ! 244: head->so_qlen++; ! 245: so->so_q = 0; ! 246: for (prev = &(head->so_q); *prev; ) ! 247: prev = &((*prev)->so_q); ! 248: } ! 249: *prev = so; ! 250: } ! 251: ! 252: int ! 253: soqremque(so, q) ! 254: register struct socket *so; ! 255: int q; ! 256: { ! 257: register struct socket *head, *prev, *next; ! 258: ! 259: head = so->so_head; ! 260: prev = head; ! 261: for (;;) { ! 262: next = q ? prev->so_q : prev->so_q0; ! 263: if (next == so) ! 264: break; ! 265: if (next == 0) ! 266: return (0); ! 267: prev = next; ! 268: } ! 269: if (q == 0) { ! 270: prev->so_q0 = next->so_q0; ! 271: head->so_q0len--; ! 272: } else { ! 273: prev->so_q = next->so_q; ! 274: head->so_qlen--; ! 275: } ! 276: next->so_q0 = next->so_q = 0; ! 277: next->so_head = 0; ! 278: return (1); ! 279: } ! 280: ! 281: /* ! 282: * Socantsendmore indicates that no more data will be sent on the ! 283: * socket; it would normally be applied to a socket when the user ! 284: * informs the system that no more data is to be sent, by the protocol ! 285: * code (in case PRU_SHUTDOWN). Socantrcvmore indicates that no more data ! 286: * will be received, and will normally be applied to the socket by a ! 287: * protocol when it detects that the peer will send no more data. ! 288: * Data queued for reading in the socket may yet be read. ! 289: */ ! 290: ! 291: void ! 292: socantsendmore(so) ! 293: struct socket *so; ! 294: { ! 295: ! 296: so->so_state |= SS_CANTSENDMORE; ! 297: sowwakeup(so); ! 298: } ! 299: ! 300: void ! 301: socantrcvmore(so) ! 302: struct socket *so; ! 303: { ! 304: ! 305: so->so_state |= SS_CANTRCVMORE; ! 306: sorwakeup(so); ! 307: } ! 308: ! 309: /* ! 310: * Wait for data to arrive at/drain from a socket buffer. ! 311: */ ! 312: int ! 313: sbwait(sb) ! 314: struct sockbuf *sb; ! 315: { ! 316: ! 317: sb->sb_flags |= SB_WAIT; ! 318: return (tsleep((caddr_t)&sb->sb_cc, ! 319: (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK | PCATCH, netio, ! 320: sb->sb_timeo)); ! 321: } ! 322: ! 323: /* ! 324: * Lock a sockbuf already known to be locked; ! 325: * return any error returned from sleep (EINTR). ! 326: */ ! 327: int ! 328: sb_lock(sb) ! 329: register struct sockbuf *sb; ! 330: { ! 331: int error; ! 332: ! 333: while (sb->sb_flags & SB_LOCK) { ! 334: sb->sb_flags |= SB_WANT; ! 335: if (error = tsleep((caddr_t)&sb->sb_flags, ! 336: (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK|PCATCH, ! 337: netio, 0)) ! 338: return (error); ! 339: } ! 340: sb->sb_flags |= SB_LOCK; ! 341: return (0); ! 342: } ! 343: ! 344: /* ! 345: * Wakeup processes waiting on a socket buffer. ! 346: * Do asynchronous notification via SIGIO ! 347: * if the socket has the SS_ASYNC flag set. ! 348: */ ! 349: void ! 350: sowakeup(so, sb) ! 351: register struct socket *so; ! 352: register struct sockbuf *sb; ! 353: { ! 354: struct proc *p; ! 355: ! 356: selwakeup(&sb->sb_sel); ! 357: sb->sb_flags &= ~SB_SEL; ! 358: if (sb->sb_flags & SB_WAIT) { ! 359: sb->sb_flags &= ~SB_WAIT; ! 360: wakeup((caddr_t)&sb->sb_cc); ! 361: } ! 362: if (so->so_state & SS_ASYNC) { ! 363: if (so->so_pgid < 0) ! 364: gsignal(-so->so_pgid, SIGIO); ! 365: else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) ! 366: psignal(p, SIGIO); ! 367: } ! 368: } ! 369: ! 370: /* ! 371: * Socket buffer (struct sockbuf) utility routines. ! 372: * ! 373: * Each socket contains two socket buffers: one for sending data and ! 374: * one for receiving data. Each buffer contains a queue of mbufs, ! 375: * information about the number of mbufs and amount of data in the ! 376: * queue, and other fields allowing select() statements and notification ! 377: * on data availability to be implemented. ! 378: * ! 379: * Data stored in a socket buffer is maintained as a list of records. ! 380: * Each record is a list of mbufs chained together with the m_next ! 381: * field. Records are chained together with the m_nextpkt field. The upper ! 382: * level routine soreceive() expects the following conventions to be ! 383: * observed when placing information in the receive buffer: ! 384: * ! 385: * 1. If the protocol requires each message be preceded by the sender's ! 386: * name, then a record containing that name must be present before ! 387: * any associated data (mbuf's must be of type MT_SONAME). ! 388: * 2. If the protocol supports the exchange of ``access rights'' (really ! 389: * just additional data associated with the message), and there are ! 390: * ``rights'' to be received, then a record containing this data ! 391: * should be present (mbuf's must be of type MT_RIGHTS). ! 392: * 3. If a name or rights record exists, then it must be followed by ! 393: * a data record, perhaps of zero length. ! 394: * ! 395: * Before using a new socket structure it is first necessary to reserve ! 396: * buffer space to the socket, by calling sbreserve(). This should commit ! 397: * some of the available buffer space in the system buffer pool for the ! 398: * socket (currently, it does nothing but enforce limits). The space ! 399: * should be released by calling sbrelease() when the socket is destroyed. ! 400: */ ! 401: ! 402: int ! 403: soreserve(so, sndcc, rcvcc) ! 404: register struct socket *so; ! 405: u_long sndcc, rcvcc; ! 406: { ! 407: ! 408: if (sbreserve(&so->so_snd, sndcc) == 0) ! 409: goto bad; ! 410: if (sbreserve(&so->so_rcv, rcvcc) == 0) ! 411: goto bad2; ! 412: if (so->so_rcv.sb_lowat == 0) ! 413: so->so_rcv.sb_lowat = 1; ! 414: if (so->so_snd.sb_lowat == 0) ! 415: so->so_snd.sb_lowat = MCLBYTES; ! 416: if (so->so_snd.sb_lowat > so->so_snd.sb_hiwat) ! 417: so->so_snd.sb_lowat = so->so_snd.sb_hiwat; ! 418: return (0); ! 419: bad2: ! 420: sbrelease(&so->so_snd); ! 421: bad: ! 422: return (ENOBUFS); ! 423: } ! 424: ! 425: /* ! 426: * Allot mbufs to a sockbuf. ! 427: * Attempt to scale mbmax so that mbcnt doesn't become limiting ! 428: * if buffering efficiency is near the normal case. ! 429: */ ! 430: int ! 431: sbreserve(sb, cc) ! 432: struct sockbuf *sb; ! 433: u_long cc; ! 434: { ! 435: ! 436: if (cc > sb_max * MCLBYTES / (MSIZE + MCLBYTES)) ! 437: return (0); ! 438: sb->sb_hiwat = cc; ! 439: sb->sb_mbmax = min(cc * 2, sb_max); ! 440: if (sb->sb_lowat > sb->sb_hiwat) ! 441: sb->sb_lowat = sb->sb_hiwat; ! 442: return (1); ! 443: } ! 444: ! 445: /* ! 446: * Free mbufs held by a socket, and reserved mbuf space. ! 447: */ ! 448: void ! 449: sbrelease(sb) ! 450: struct sockbuf *sb; ! 451: { ! 452: ! 453: sbflush(sb); ! 454: sb->sb_hiwat = sb->sb_mbmax = 0; ! 455: ! 456: { ! 457: int oldpri = splimp(); ! 458: selthreadclear(&sb->sb_sel); ! 459: splx(oldpri); ! 460: } ! 461: } ! 462: ! 463: /* ! 464: * Routines to add and remove ! 465: * data from an mbuf queue. ! 466: * ! 467: * The routines sbappend() or sbappendrecord() are normally called to ! 468: * append new mbufs to a socket buffer, after checking that adequate ! 469: * space is available, comparing the function sbspace() with the amount ! 470: * of data to be added. sbappendrecord() differs from sbappend() in ! 471: * that data supplied is treated as the beginning of a new record. ! 472: * To place a sender's address, optional access rights, and data in a ! 473: * socket receive buffer, sbappendaddr() should be used. To place ! 474: * access rights and data in a socket receive buffer, sbappendrights() ! 475: * should be used. In either case, the new data begins a new record. ! 476: * Note that unlike sbappend() and sbappendrecord(), these routines check ! 477: * for the caller that there will be enough space to store the data. ! 478: * Each fails if there is not enough space, or if it cannot find mbufs ! 479: * to store additional information in. ! 480: * ! 481: * Reliable protocols may use the socket send buffer to hold data ! 482: * awaiting acknowledgement. Data is normally copied from a socket ! 483: * send buffer in a protocol with m_copy for output to a peer, ! 484: * and then removing the data from the socket buffer with sbdrop() ! 485: * or sbdroprecord() when the data is acknowledged by the peer. ! 486: */ ! 487: ! 488: /* ! 489: * Append mbuf chain m to the last record in the ! 490: * socket buffer sb. The additional space associated ! 491: * the mbuf chain is recorded in sb. Empty mbufs are ! 492: * discarded and mbufs are compacted where possible. ! 493: */ ! 494: void ! 495: sbappend(sb, m) ! 496: struct sockbuf *sb; ! 497: struct mbuf *m; ! 498: { ! 499: register struct mbuf *n; ! 500: ! 501: if (m == 0) ! 502: return; ! 503: if (n = sb->sb_mb) { ! 504: while (n->m_nextpkt) ! 505: n = n->m_nextpkt; ! 506: do { ! 507: if (n->m_flags & M_EOR) { ! 508: sbappendrecord(sb, m); /* XXXXXX!!!! */ ! 509: return; ! 510: } ! 511: } while (n->m_next && (n = n->m_next)); ! 512: } ! 513: sbcompress(sb, m, n); ! 514: } ! 515: ! 516: #ifdef SOCKBUF_DEBUG ! 517: void ! 518: sbcheck(sb) ! 519: register struct sockbuf *sb; ! 520: { ! 521: register struct mbuf *m; ! 522: register int len = 0, mbcnt = 0; ! 523: ! 524: for (m = sb->sb_mb; m; m = m->m_next) { ! 525: len += m->m_len; ! 526: mbcnt += MSIZE; ! 527: if (m->m_flags & M_EXT) ! 528: mbcnt += m->m_ext.ext_size; ! 529: if (m->m_nextpkt) ! 530: panic("sbcheck nextpkt"); ! 531: } ! 532: if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { ! 533: printf("cc %d != %d || mbcnt %d != %d\n", len, sb->sb_cc, ! 534: mbcnt, sb->sb_mbcnt); ! 535: panic("sbcheck"); ! 536: } ! 537: } ! 538: #endif ! 539: ! 540: /* ! 541: * As above, except the mbuf chain ! 542: * begins a new record. ! 543: */ ! 544: void ! 545: sbappendrecord(sb, m0) ! 546: register struct sockbuf *sb; ! 547: register struct mbuf *m0; ! 548: { ! 549: register struct mbuf *m; ! 550: ! 551: if (m0 == 0) ! 552: return; ! 553: if (m = sb->sb_mb) ! 554: while (m->m_nextpkt) ! 555: m = m->m_nextpkt; ! 556: /* ! 557: * Put the first mbuf on the queue. ! 558: * Note this permits zero length records. ! 559: */ ! 560: sballoc(sb, m0); ! 561: if (m) ! 562: m->m_nextpkt = m0; ! 563: else ! 564: sb->sb_mb = m0; ! 565: m = m0->m_next; ! 566: m0->m_next = 0; ! 567: if (m && (m0->m_flags & M_EOR)) { ! 568: m0->m_flags &= ~M_EOR; ! 569: m->m_flags |= M_EOR; ! 570: } ! 571: sbcompress(sb, m, m0); ! 572: } ! 573: ! 574: /* ! 575: * As above except that OOB data ! 576: * is inserted at the beginning of the sockbuf, ! 577: * but after any other OOB data. ! 578: */ ! 579: void ! 580: sbinsertoob(sb, m0) ! 581: register struct sockbuf *sb; ! 582: register struct mbuf *m0; ! 583: { ! 584: register struct mbuf *m; ! 585: register struct mbuf **mp; ! 586: ! 587: if (m0 == 0) ! 588: return; ! 589: for (mp = &sb->sb_mb; m = *mp; mp = &((*mp)->m_nextpkt)) { ! 590: again: ! 591: switch (m->m_type) { ! 592: ! 593: case MT_OOBDATA: ! 594: continue; /* WANT next train */ ! 595: ! 596: case MT_CONTROL: ! 597: if (m = m->m_next) ! 598: goto again; /* inspect THIS train further */ ! 599: } ! 600: break; ! 601: } ! 602: /* ! 603: * Put the first mbuf on the queue. ! 604: * Note this permits zero length records. ! 605: */ ! 606: sballoc(sb, m0); ! 607: m0->m_nextpkt = *mp; ! 608: *mp = m0; ! 609: m = m0->m_next; ! 610: m0->m_next = 0; ! 611: if (m && (m0->m_flags & M_EOR)) { ! 612: m0->m_flags &= ~M_EOR; ! 613: m->m_flags |= M_EOR; ! 614: } ! 615: sbcompress(sb, m, m0); ! 616: } ! 617: ! 618: /* ! 619: * Append address and data, and optionally, control (ancillary) data ! 620: * to the receive queue of a socket. If present, ! 621: * m0 must include a packet header with total length. ! 622: * Returns 0 if no space in sockbuf or insufficient mbufs. ! 623: */ ! 624: int ! 625: sbappendaddr(sb, asa, m0, control) ! 626: register struct sockbuf *sb; ! 627: struct sockaddr *asa; ! 628: struct mbuf *m0, *control; ! 629: { ! 630: register struct mbuf *m, *n; ! 631: int space = asa->sa_len; ! 632: ! 633: if (m0 && (m0->m_flags & M_PKTHDR) == 0) ! 634: panic("sbappendaddr"); ! 635: if (m0) ! 636: space += m0->m_pkthdr.len; ! 637: for (n = control; n; n = n->m_next) { ! 638: space += n->m_len; ! 639: if (n->m_next == 0) /* keep pointer to last control buf */ ! 640: break; ! 641: } ! 642: if (space > sbspace(sb)) ! 643: return (0); ! 644: if (asa->sa_len > MLEN) ! 645: return (0); ! 646: MGET(m, M_DONTWAIT, MT_SONAME); ! 647: if (m == 0) ! 648: return (0); ! 649: m->m_len = asa->sa_len; ! 650: bcopy((caddr_t)asa, mtod(m, caddr_t), asa->sa_len); ! 651: if (n) ! 652: n->m_next = m0; /* concatenate data to control */ ! 653: else ! 654: control = m0; ! 655: m->m_next = control; ! 656: for (n = m; n; n = n->m_next) ! 657: sballoc(sb, n); ! 658: if (n = sb->sb_mb) { ! 659: while (n->m_nextpkt) ! 660: n = n->m_nextpkt; ! 661: n->m_nextpkt = m; ! 662: } else ! 663: sb->sb_mb = m; ! 664: postevent(0,sb,EV_RWBYTES); ! 665: return (1); ! 666: } ! 667: ! 668: int ! 669: sbappendcontrol(sb, m0, control) ! 670: struct sockbuf *sb; ! 671: struct mbuf *m0, *control; ! 672: { ! 673: register struct mbuf *m, *n; ! 674: int space = 0; ! 675: ! 676: if (control == 0) ! 677: panic("sbappendcontrol"); ! 678: for (m = control; ; m = m->m_next) { ! 679: space += m->m_len; ! 680: if (m->m_next == 0) ! 681: break; ! 682: } ! 683: n = m; /* save pointer to last control buffer */ ! 684: for (m = m0; m; m = m->m_next) ! 685: space += m->m_len; ! 686: if (space > sbspace(sb)) ! 687: return (0); ! 688: n->m_next = m0; /* concatenate data to control */ ! 689: for (m = control; m; m = m->m_next) ! 690: sballoc(sb, m); ! 691: if (n = sb->sb_mb) { ! 692: while (n->m_nextpkt) ! 693: n = n->m_nextpkt; ! 694: n->m_nextpkt = control; ! 695: } else ! 696: sb->sb_mb = control; ! 697: postevent(0,sb,EV_RWBYTES); ! 698: return (1); ! 699: } ! 700: ! 701: /* ! 702: * Compress mbuf chain m into the socket ! 703: * buffer sb following mbuf n. If n ! 704: * is null, the buffer is presumed empty. ! 705: */ ! 706: void ! 707: sbcompress(sb, m, n) ! 708: register struct sockbuf *sb; ! 709: register struct mbuf *m, *n; ! 710: { ! 711: register int eor = 0; ! 712: register struct mbuf *o; ! 713: ! 714: while (m) { ! 715: eor |= m->m_flags & M_EOR; ! 716: if (m->m_len == 0 && ! 717: (eor == 0 || ! 718: (((o = m->m_next) || (o = n)) && ! 719: o->m_type == m->m_type))) { ! 720: m = m_free(m); ! 721: continue; ! 722: } ! 723: if (n && (n->m_flags & (M_EXT | M_EOR)) == 0 && ! 724: (n->m_data + n->m_len + m->m_len) < &n->m_dat[MLEN] && ! 725: n->m_type == m->m_type) { ! 726: bcopy(mtod(m, caddr_t), mtod(n, caddr_t) + n->m_len, ! 727: (unsigned)m->m_len); ! 728: n->m_len += m->m_len; ! 729: sb->sb_cc += m->m_len; ! 730: m = m_free(m); ! 731: continue; ! 732: } ! 733: if (n) ! 734: n->m_next = m; ! 735: else ! 736: sb->sb_mb = m; ! 737: sballoc(sb, m); ! 738: n = m; ! 739: m->m_flags &= ~M_EOR; ! 740: m = m->m_next; ! 741: n->m_next = 0; ! 742: } ! 743: if (eor) { ! 744: if (n) ! 745: n->m_flags |= eor; ! 746: else ! 747: printf("semi-panic: sbcompress\n"); ! 748: } ! 749: postevent(0,sb, EV_RWBYTES); ! 750: } ! 751: ! 752: /* ! 753: * Free all mbufs in a sockbuf. ! 754: * Check that all resources are reclaimed. ! 755: */ ! 756: void ! 757: sbflush(sb) ! 758: register struct sockbuf *sb; ! 759: { ! 760: ! 761: if (sb->sb_flags & SB_LOCK) ! 762: panic("sbflush"); ! 763: while (sb->sb_mbcnt) ! 764: sbdrop(sb, (int)sb->sb_cc); ! 765: if (sb->sb_cc || sb->sb_mb) ! 766: panic("sbflush 2"); ! 767: postevent(0, sb, EV_RWBYTES); ! 768: } ! 769: ! 770: /* ! 771: * Drop data from (the front of) a sockbuf. ! 772: */ ! 773: void ! 774: sbdrop(sb, len) ! 775: register struct sockbuf *sb; ! 776: register int len; ! 777: { ! 778: register struct mbuf *m, *mn; ! 779: struct mbuf *next; ! 780: ! 781: next = (m = sb->sb_mb) ? m->m_nextpkt : 0; ! 782: while (len > 0) { ! 783: if (m == 0) { ! 784: if (next == 0) ! 785: panic("sbdrop"); ! 786: m = next; ! 787: next = m->m_nextpkt; ! 788: continue; ! 789: } ! 790: if (m->m_len > len) { ! 791: m->m_len -= len; ! 792: m->m_data += len; ! 793: sb->sb_cc -= len; ! 794: break; ! 795: } ! 796: len -= m->m_len; ! 797: sbfree(sb, m); ! 798: MFREE(m, mn); ! 799: m = mn; ! 800: } ! 801: while (m && m->m_len == 0) { ! 802: sbfree(sb, m); ! 803: MFREE(m, mn); ! 804: m = mn; ! 805: } ! 806: if (m) { ! 807: sb->sb_mb = m; ! 808: m->m_nextpkt = next; ! 809: } else ! 810: sb->sb_mb = next; ! 811: postevent(0, sb, EV_RWBYTES); ! 812: } ! 813: ! 814: /* ! 815: * Drop a record off the front of a sockbuf ! 816: * and move the next record to the front. ! 817: */ ! 818: void ! 819: sbdroprecord(sb) ! 820: register struct sockbuf *sb; ! 821: { ! 822: register struct mbuf *m, *mn; ! 823: ! 824: m = sb->sb_mb; ! 825: if (m) { ! 826: sb->sb_mb = m->m_nextpkt; ! 827: do { ! 828: sbfree(sb, m); ! 829: MFREE(m, mn); ! 830: } while (m = mn); ! 831: } ! 832: postevent(0, sb, EV_RWBYTES); ! 833: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.