xref: /csrg-svn/sys/kern/uipc_socket2.c (revision 4903)
1*4903Swnj /*	uipc_socket2.c	4.1	81/11/15	*/
2*4903Swnj 
3*4903Swnj #include "../h/param.h"
4*4903Swnj #include "../h/systm.h"
5*4903Swnj #include "../h/dir.h"
6*4903Swnj #include "../h/user.h"
7*4903Swnj #include "../h/proc.h"
8*4903Swnj #include "../h/file.h"
9*4903Swnj #include "../h/inode.h"
10*4903Swnj #include "../h/buf.h"
11*4903Swnj #include "../h/mbuf.h"
12*4903Swnj #include "../h/protocol.h"
13*4903Swnj #include "../h/protosw.h"
14*4903Swnj #include "../h/socket.h"
15*4903Swnj #include "../h/socketvar.h"
16*4903Swnj #include "../h/inaddr.h"
17*4903Swnj #include "../net/inet.h"
18*4903Swnj #include "../net/inet_systm.h"
19*4903Swnj 
20*4903Swnj /*
21*4903Swnj  * Primitive routines for operating on sockets and socket buffers
22*4903Swnj  */
23*4903Swnj 
24*4903Swnj /*
25*4903Swnj  * Procedures to manipulate state flags of socket
26*4903Swnj  * and do appropriate wakeups.
27*4903Swnj  */
28*4903Swnj soisconnecting(so)
29*4903Swnj 	struct socket *so;
30*4903Swnj {
31*4903Swnj 
32*4903Swnj 	so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING);
33*4903Swnj 	so->so_state |= SS_ISCONNECTING;
34*4903Swnj 	wakeup((caddr_t)&so->so_timeo);
35*4903Swnj }
36*4903Swnj 
37*4903Swnj soisconnected(so)
38*4903Swnj 	struct socket *so;
39*4903Swnj {
40*4903Swnj 
41*4903Swnj 	so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING);
42*4903Swnj 	so->so_state |= SS_ISCONNECTED;
43*4903Swnj 	wakeup((caddr_t)&so->so_timeo);
44*4903Swnj }
45*4903Swnj 
46*4903Swnj soisdisconnecting(so)
47*4903Swnj 	struct socket *so;
48*4903Swnj {
49*4903Swnj 
50*4903Swnj 	so->so_state &= ~(SS_ISCONNECTED|SS_ISCONNECTING);
51*4903Swnj 	so->so_state |= (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE);
52*4903Swnj 	wakeup((caddr_t)&so->so_timeo);
53*4903Swnj }
54*4903Swnj 
55*4903Swnj soisdisconnected(so)
56*4903Swnj 	struct socket *so;
57*4903Swnj {
58*4903Swnj 
59*4903Swnj 	so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
60*4903Swnj 	so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE);
61*4903Swnj 	wakeup((caddr_t)&so->so_timeo);
62*4903Swnj 	sowwakeup(so);
63*4903Swnj 	sorwakeup(so);
64*4903Swnj }
65*4903Swnj 
66*4903Swnj /*
67*4903Swnj  * Select a socket.
68*4903Swnj  */
69*4903Swnj soselect(so, flag)
70*4903Swnj 	register struct socket *so;
71*4903Swnj 	int flag;
72*4903Swnj {
73*4903Swnj 
74*4903Swnj 	if (flag & FREAD) {
75*4903Swnj 		if (soreadable(so))
76*4903Swnj 			return (1);
77*4903Swnj 		sbselqueue(&so->so_rcv);
78*4903Swnj 	}
79*4903Swnj 	if (flag & FWRITE) {
80*4903Swnj 		if (sowriteable(so))
81*4903Swnj 			return (1);
82*4903Swnj 		sbselqueue(&so->so_snd);
83*4903Swnj 	}
84*4903Swnj 	return (0);
85*4903Swnj }
86*4903Swnj 
87*4903Swnj /*
88*4903Swnj  * Queue a process for a select on a socket buffer.
89*4903Swnj  */
90*4903Swnj sbselqueue(sb)
91*4903Swnj 	struct sockbuf *sb;
92*4903Swnj {
93*4903Swnj 	register struct proc *p;
94*4903Swnj 
95*4903Swnj 	if ((p = sb->sb_sel) && p->p_wchan == (caddr_t)select)
96*4903Swnj 		sb->sb_flags |= SB_COLL;
97*4903Swnj 	else
98*4903Swnj 		sb->sb_sel = u.u_procp;
99*4903Swnj }
100*4903Swnj 
101*4903Swnj /*
102*4903Swnj  * Wakeup processes waiting on a socket buffer.
103*4903Swnj  */
104*4903Swnj sbwakeup(sb)
105*4903Swnj 	struct sockbuf *sb;
106*4903Swnj {
107*4903Swnj 
108*4903Swnj 	if (sb->sb_sel) {
109*4903Swnj 		selwakeup(sb->sb_sel, sb->sb_flags & SB_COLL);
110*4903Swnj 		sb->sb_sel = 0;
111*4903Swnj 		sb->sb_flags &= ~SB_COLL;
112*4903Swnj 	}
113*4903Swnj 	if (sb->sb_flags & SB_WAIT) {
114*4903Swnj 		sb->sb_flags &= ~SB_WAIT;
115*4903Swnj 		wakeup((caddr_t)sb->sb_cc);
116*4903Swnj 	}
117*4903Swnj }
118*4903Swnj 
119*4903Swnj /*
120*4903Swnj  * Allot mbufs to a sockbuf.
121*4903Swnj  */
122*4903Swnj sbreserve(sb, cc)
123*4903Swnj 	struct sockbuf *sb;
124*4903Swnj {
125*4903Swnj 
126*4903Swnj 	if (m_reserve(cc) == 0)
127*4903Swnj 		return (0);
128*4903Swnj 	sb->sb_cc = cc;
129*4903Swnj 	sb->sb_mbcnt = (cc*2)/MSIZE;
130*4903Swnj }
131*4903Swnj 
132*4903Swnj /*
133*4903Swnj  * Free mbufs held by a socket, and reserved mbuf space.
134*4903Swnj  */
135*4903Swnj sbrelease(sb)
136*4903Swnj 	struct sockbuf *sb;
137*4903Swnj {
138*4903Swnj 
139*4903Swnj 	sbflush(sb);
140*4903Swnj 	m_release(sb->sb_cc);
141*4903Swnj 	sb->sb_cc = sb->sb_mbcnt = 0;
142*4903Swnj }
143*4903Swnj 
144*4903Swnj /*
145*4903Swnj  * Routines to add (at the end) and remove (from the beginning)
146*4903Swnj  * data from a mbuf queue.
147*4903Swnj  */
148*4903Swnj 
149*4903Swnj /*
150*4903Swnj  * Append mbuf queue m to sockbuf sb.
151*4903Swnj  */
152*4903Swnj sbappend(sb, m)
153*4903Swnj 	register struct mbuf *m;
154*4903Swnj 	register struct sockbuf *sb;
155*4903Swnj {
156*4903Swnj 	register struct mbuf **np, *n;
157*4903Swnj 
158*4903Swnj 	np = &sb->sb_mb;
159*4903Swnj 	while ((n = *np) && n->m_next)
160*4903Swnj 		np = &n->m_next;
161*4903Swnj 	while (m) {
162*4903Swnj 		if (n && n->m_off <= MMAXOFF && m->m_off <= MMAXOFF &&
163*4903Swnj 		   (int)n->m_act == 0 && (int)m->m_act == 0 &&
164*4903Swnj 		   (n->m_off + n->m_len + m->m_off) <= MMAXOFF) {
165*4903Swnj 			bcopy(mtod(m, caddr_t), mtod(n, caddr_t), m->m_len);
166*4903Swnj 			n->m_len += m->m_len;
167*4903Swnj 			sb->sb_cc += m->m_len;
168*4903Swnj 			m = m_free(m);
169*4903Swnj 			continue;
170*4903Swnj 		}
171*4903Swnj 		sballoc(sb, m);
172*4903Swnj 		*np = m;
173*4903Swnj 		n = m;
174*4903Swnj 		np = &n->m_next;
175*4903Swnj 		m = m->m_next;
176*4903Swnj 	}
177*4903Swnj }
178*4903Swnj 
179*4903Swnj /*
180*4903Swnj  * Free all mbufs on a sockbuf mbuf chain.
181*4903Swnj  * Check that resource allocations return to 0.
182*4903Swnj  */
183*4903Swnj sbflush(sb)
184*4903Swnj 	struct sockbuf *sb;
185*4903Swnj {
186*4903Swnj 
187*4903Swnj 	if (sb->sb_flags & SB_LOCK)
188*4903Swnj 		panic("sbflush");
189*4903Swnj 	sbdrop(sb, sb->sb_cc);
190*4903Swnj 	if (sb->sb_cc || sb->sb_mbcnt || sb->sb_mb)
191*4903Swnj 		panic("sbflush 2");
192*4903Swnj }
193*4903Swnj 
194*4903Swnj /*
195*4903Swnj  * Drop data from (the front of) a sockbuf chain.
196*4903Swnj  */
197*4903Swnj sbdrop(sb, len)
198*4903Swnj 	register struct sockbuf *sb;
199*4903Swnj 	register int len;
200*4903Swnj {
201*4903Swnj 	register struct mbuf *m = sb->sb_mb, *mn;
202*4903Swnj 
203*4903Swnj 	while (len > 0) {
204*4903Swnj 		if (m == 0)
205*4903Swnj 			panic("sbdrop");
206*4903Swnj 		if (m->m_len <= len) {
207*4903Swnj 			len -= m->m_len;
208*4903Swnj 			sbfree(sb, m);
209*4903Swnj 			MFREE(m, mn);
210*4903Swnj 			m = mn;
211*4903Swnj 		} else {
212*4903Swnj 			m->m_len -= len;
213*4903Swnj 			m->m_off += len;
214*4903Swnj 			sb->sb_cc -= len;
215*4903Swnj 			break;
216*4903Swnj 		}
217*4903Swnj 	}
218*4903Swnj 	sb->sb_mb = m;
219*4903Swnj }
220*4903Swnj 
221*4903Swnj struct mbuf *
222*4903Swnj sb_copy(sb, off, len)
223*4903Swnj 	struct sockbuf *sb;
224*4903Swnj 	int off;
225*4903Swnj 	register int len;
226*4903Swnj {
227*4903Swnj 	register struct mbuf *m, *n, **np;
228*4903Swnj 	struct mbuf *top, *p;
229*4903Swnj COUNT(SB_COPY);
230*4903Swnj 
231*4903Swnj 	if (len == 0)
232*4903Swnj 		return (0);
233*4903Swnj 	if (off < 0 || len < 0)
234*4903Swnj 		panic("sb_copy");
235*4903Swnj 	m = sb->sb_mb;
236*4903Swnj 	while (off > 0) {
237*4903Swnj 		if (m == 0)
238*4903Swnj 			panic("sb_copy");
239*4903Swnj 		if (off < m->m_len)
240*4903Swnj 			break;
241*4903Swnj 		off -= m->m_len;
242*4903Swnj 		m = m->m_next;
243*4903Swnj 	}
244*4903Swnj 	np = &top;
245*4903Swnj 	top = 0;
246*4903Swnj 	while (len > 0) {
247*4903Swnj 		MGET(n, 1);
248*4903Swnj 		*np = n;
249*4903Swnj 		if (n == 0)
250*4903Swnj 			goto nospace;
251*4903Swnj 		if (m == 0)
252*4903Swnj 			panic("sb_copy");
253*4903Swnj 		n->m_len = MIN(len, m->m_len - off);
254*4903Swnj 		if (m->m_off > MMAXOFF) {
255*4903Swnj 			p = mtod(m, struct mbuf *);
256*4903Swnj 			n->m_off = ((int)p - (int)n) + off;
257*4903Swnj 			mprefcnt[mtopf(p)]++;
258*4903Swnj 		} else {
259*4903Swnj 			n->m_off = MMINOFF;
260*4903Swnj 			bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
261*4903Swnj 			    n->m_len);
262*4903Swnj 		}
263*4903Swnj 		len -= n->m_len;
264*4903Swnj 		off = 0;
265*4903Swnj 		m = m->m_next;
266*4903Swnj 		np = &n->m_next;
267*4903Swnj 	}
268*4903Swnj 	return (top);
269*4903Swnj nospace:
270*4903Swnj 	printf("snd_copy: no space\n");
271*4903Swnj 	m_freem(top);
272*4903Swnj 	return (0);
273*4903Swnj }
274