xref: /csrg-svn/sys/kern/uipc_socket2.c (revision 4917)
1*4917Swnj /*	uipc_socket2.c	4.2	81/11/16	*/
24903Swnj 
34903Swnj #include "../h/param.h"
44903Swnj #include "../h/systm.h"
54903Swnj #include "../h/dir.h"
64903Swnj #include "../h/user.h"
74903Swnj #include "../h/proc.h"
84903Swnj #include "../h/file.h"
94903Swnj #include "../h/inode.h"
104903Swnj #include "../h/buf.h"
114903Swnj #include "../h/mbuf.h"
124903Swnj #include "../h/protocol.h"
134903Swnj #include "../h/protosw.h"
144903Swnj #include "../h/socket.h"
154903Swnj #include "../h/socketvar.h"
164903Swnj #include "../h/inaddr.h"
174903Swnj #include "../net/inet.h"
184903Swnj #include "../net/inet_systm.h"
194903Swnj 
204903Swnj /*
214903Swnj  * Primitive routines for operating on sockets and socket buffers
224903Swnj  */
234903Swnj 
244903Swnj /*
254903Swnj  * Procedures to manipulate state flags of socket
264903Swnj  * and do appropriate wakeups.
274903Swnj  */
284903Swnj soisconnecting(so)
294903Swnj 	struct socket *so;
304903Swnj {
314903Swnj 
324903Swnj 	so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING);
334903Swnj 	so->so_state |= SS_ISCONNECTING;
344903Swnj 	wakeup((caddr_t)&so->so_timeo);
354903Swnj }
364903Swnj 
374903Swnj soisconnected(so)
384903Swnj 	struct socket *so;
394903Swnj {
404903Swnj 
414903Swnj 	so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING);
424903Swnj 	so->so_state |= SS_ISCONNECTED;
434903Swnj 	wakeup((caddr_t)&so->so_timeo);
444903Swnj }
454903Swnj 
464903Swnj soisdisconnecting(so)
474903Swnj 	struct socket *so;
484903Swnj {
494903Swnj 
504903Swnj 	so->so_state &= ~(SS_ISCONNECTED|SS_ISCONNECTING);
514903Swnj 	so->so_state |= (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE);
524903Swnj 	wakeup((caddr_t)&so->so_timeo);
534903Swnj }
544903Swnj 
554903Swnj soisdisconnected(so)
564903Swnj 	struct socket *so;
574903Swnj {
584903Swnj 
594903Swnj 	so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
604903Swnj 	so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE);
614903Swnj 	wakeup((caddr_t)&so->so_timeo);
624903Swnj 	sowwakeup(so);
634903Swnj 	sorwakeup(so);
644903Swnj }
654903Swnj 
66*4917Swnj socantsendmore(so)
67*4917Swnj 	struct socket *so;
68*4917Swnj {
69*4917Swnj 
70*4917Swnj 	so->so_state |= SS_CANTSENDMORE;
71*4917Swnj 	sowwakeup(so);
72*4917Swnj }
73*4917Swnj 
74*4917Swnj socantrcvmore(so)
75*4917Swnj 	struct socket *so;
76*4917Swnj {
77*4917Swnj 
78*4917Swnj 	so->so_state |= SS_CANTRCVMORE;
79*4917Swnj 	sorwakeup(so);
80*4917Swnj }
81*4917Swnj 
824903Swnj /*
834903Swnj  * Select a socket.
844903Swnj  */
854903Swnj soselect(so, flag)
864903Swnj 	register struct socket *so;
874903Swnj 	int flag;
884903Swnj {
894903Swnj 
904903Swnj 	if (flag & FREAD) {
914903Swnj 		if (soreadable(so))
924903Swnj 			return (1);
934903Swnj 		sbselqueue(&so->so_rcv);
944903Swnj 	}
954903Swnj 	if (flag & FWRITE) {
964903Swnj 		if (sowriteable(so))
974903Swnj 			return (1);
984903Swnj 		sbselqueue(&so->so_snd);
994903Swnj 	}
1004903Swnj 	return (0);
1014903Swnj }
1024903Swnj 
1034903Swnj /*
1044903Swnj  * Queue a process for a select on a socket buffer.
1054903Swnj  */
1064903Swnj sbselqueue(sb)
1074903Swnj 	struct sockbuf *sb;
1084903Swnj {
1094903Swnj 	register struct proc *p;
1104903Swnj 
111*4917Swnj 	if ((p = sb->sb_sel) && p->p_wchan == (caddr_t)&selwait)
1124903Swnj 		sb->sb_flags |= SB_COLL;
1134903Swnj 	else
1144903Swnj 		sb->sb_sel = u.u_procp;
1154903Swnj }
1164903Swnj 
1174903Swnj /*
118*4917Swnj  * Wait for data to arrive at/drain from a socket buffer.
119*4917Swnj  */
120*4917Swnj sbwait(sb)
121*4917Swnj 	struct sockbuf *sb;
122*4917Swnj {
123*4917Swnj 
124*4917Swnj 	sb->sb_flags |= SB_WAIT;
125*4917Swnj 	sleep((caddr_t)&sb->sb_cc, PZERO+1);
126*4917Swnj }
127*4917Swnj 
128*4917Swnj /*
1294903Swnj  * Wakeup processes waiting on a socket buffer.
1304903Swnj  */
1314903Swnj sbwakeup(sb)
1324903Swnj 	struct sockbuf *sb;
1334903Swnj {
1344903Swnj 
1354903Swnj 	if (sb->sb_sel) {
1364903Swnj 		selwakeup(sb->sb_sel, sb->sb_flags & SB_COLL);
1374903Swnj 		sb->sb_sel = 0;
1384903Swnj 		sb->sb_flags &= ~SB_COLL;
1394903Swnj 	}
1404903Swnj 	if (sb->sb_flags & SB_WAIT) {
1414903Swnj 		sb->sb_flags &= ~SB_WAIT;
1424903Swnj 		wakeup((caddr_t)sb->sb_cc);
1434903Swnj 	}
1444903Swnj }
1454903Swnj 
1464903Swnj /*
1474903Swnj  * Allot mbufs to a sockbuf.
1484903Swnj  */
1494903Swnj sbreserve(sb, cc)
1504903Swnj 	struct sockbuf *sb;
1514903Swnj {
1524903Swnj 
1534903Swnj 	if (m_reserve(cc) == 0)
1544903Swnj 		return (0);
1554903Swnj 	sb->sb_cc = cc;
1564903Swnj 	sb->sb_mbcnt = (cc*2)/MSIZE;
157*4917Swnj 	return (1);
1584903Swnj }
1594903Swnj 
1604903Swnj /*
1614903Swnj  * Free mbufs held by a socket, and reserved mbuf space.
1624903Swnj  */
1634903Swnj sbrelease(sb)
1644903Swnj 	struct sockbuf *sb;
1654903Swnj {
1664903Swnj 
1674903Swnj 	sbflush(sb);
1684903Swnj 	m_release(sb->sb_cc);
1694903Swnj 	sb->sb_cc = sb->sb_mbcnt = 0;
1704903Swnj }
1714903Swnj 
1724903Swnj /*
1734903Swnj  * Routines to add (at the end) and remove (from the beginning)
1744903Swnj  * data from a mbuf queue.
1754903Swnj  */
1764903Swnj 
1774903Swnj /*
1784903Swnj  * Append mbuf queue m to sockbuf sb.
1794903Swnj  */
1804903Swnj sbappend(sb, m)
1814903Swnj 	register struct mbuf *m;
1824903Swnj 	register struct sockbuf *sb;
1834903Swnj {
1844903Swnj 	register struct mbuf **np, *n;
1854903Swnj 
1864903Swnj 	np = &sb->sb_mb;
1874903Swnj 	while ((n = *np) && n->m_next)
1884903Swnj 		np = &n->m_next;
1894903Swnj 	while (m) {
1904903Swnj 		if (n && n->m_off <= MMAXOFF && m->m_off <= MMAXOFF &&
1914903Swnj 		   (int)n->m_act == 0 && (int)m->m_act == 0 &&
1924903Swnj 		   (n->m_off + n->m_len + m->m_off) <= MMAXOFF) {
193*4917Swnj 			bcopy(mtod(m, caddr_t), mtod(n, caddr_t),
194*4917Swnj 			    (unsigned)m->m_len);
1954903Swnj 			n->m_len += m->m_len;
1964903Swnj 			sb->sb_cc += m->m_len;
1974903Swnj 			m = m_free(m);
1984903Swnj 			continue;
1994903Swnj 		}
2004903Swnj 		sballoc(sb, m);
2014903Swnj 		*np = m;
2024903Swnj 		n = m;
2034903Swnj 		np = &n->m_next;
2044903Swnj 		m = m->m_next;
2054903Swnj 	}
2064903Swnj }
2074903Swnj 
2084903Swnj /*
2094903Swnj  * Free all mbufs on a sockbuf mbuf chain.
2104903Swnj  * Check that resource allocations return to 0.
2114903Swnj  */
2124903Swnj sbflush(sb)
2134903Swnj 	struct sockbuf *sb;
2144903Swnj {
2154903Swnj 
2164903Swnj 	if (sb->sb_flags & SB_LOCK)
2174903Swnj 		panic("sbflush");
2184903Swnj 	sbdrop(sb, sb->sb_cc);
2194903Swnj 	if (sb->sb_cc || sb->sb_mbcnt || sb->sb_mb)
2204903Swnj 		panic("sbflush 2");
2214903Swnj }
2224903Swnj 
2234903Swnj /*
2244903Swnj  * Drop data from (the front of) a sockbuf chain.
2254903Swnj  */
2264903Swnj sbdrop(sb, len)
2274903Swnj 	register struct sockbuf *sb;
2284903Swnj 	register int len;
2294903Swnj {
2304903Swnj 	register struct mbuf *m = sb->sb_mb, *mn;
2314903Swnj 
2324903Swnj 	while (len > 0) {
2334903Swnj 		if (m == 0)
2344903Swnj 			panic("sbdrop");
2354903Swnj 		if (m->m_len <= len) {
2364903Swnj 			len -= m->m_len;
2374903Swnj 			sbfree(sb, m);
2384903Swnj 			MFREE(m, mn);
2394903Swnj 			m = mn;
2404903Swnj 		} else {
2414903Swnj 			m->m_len -= len;
2424903Swnj 			m->m_off += len;
2434903Swnj 			sb->sb_cc -= len;
2444903Swnj 			break;
2454903Swnj 		}
2464903Swnj 	}
2474903Swnj 	sb->sb_mb = m;
2484903Swnj }
2494903Swnj 
2504903Swnj struct mbuf *
251*4917Swnj sbcopy(sb, off, len)
2524903Swnj 	struct sockbuf *sb;
2534903Swnj 	int off;
2544903Swnj 	register int len;
2554903Swnj {
2564903Swnj 	register struct mbuf *m, *n, **np;
2574903Swnj 	struct mbuf *top, *p;
2584903Swnj COUNT(SB_COPY);
2594903Swnj 
2604903Swnj 	if (len == 0)
2614903Swnj 		return (0);
2624903Swnj 	if (off < 0 || len < 0)
2634903Swnj 		panic("sb_copy");
2644903Swnj 	m = sb->sb_mb;
2654903Swnj 	while (off > 0) {
2664903Swnj 		if (m == 0)
2674903Swnj 			panic("sb_copy");
2684903Swnj 		if (off < m->m_len)
2694903Swnj 			break;
2704903Swnj 		off -= m->m_len;
2714903Swnj 		m = m->m_next;
2724903Swnj 	}
2734903Swnj 	np = &top;
2744903Swnj 	top = 0;
2754903Swnj 	while (len > 0) {
2764903Swnj 		MGET(n, 1);
2774903Swnj 		*np = n;
2784903Swnj 		if (n == 0)
2794903Swnj 			goto nospace;
2804903Swnj 		if (m == 0)
2814903Swnj 			panic("sb_copy");
2824903Swnj 		n->m_len = MIN(len, m->m_len - off);
2834903Swnj 		if (m->m_off > MMAXOFF) {
2844903Swnj 			p = mtod(m, struct mbuf *);
2854903Swnj 			n->m_off = ((int)p - (int)n) + off;
2864903Swnj 			mprefcnt[mtopf(p)]++;
2874903Swnj 		} else {
2884903Swnj 			n->m_off = MMINOFF;
2894903Swnj 			bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
290*4917Swnj 			    (unsigned)n->m_len);
2914903Swnj 		}
2924903Swnj 		len -= n->m_len;
2934903Swnj 		off = 0;
2944903Swnj 		m = m->m_next;
2954903Swnj 		np = &n->m_next;
2964903Swnj 	}
2974903Swnj 	return (top);
2984903Swnj nospace:
2994903Swnj 	printf("snd_copy: no space\n");
3004903Swnj 	m_freem(top);
3014903Swnj 	return (0);
3024903Swnj }
303