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