xref: /csrg-svn/sys/kern/uipc_socket2.c (revision 4903)
1 /*	uipc_socket2.c	4.1	81/11/15	*/
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 /*
67  * Select a socket.
68  */
69 soselect(so, flag)
70 	register struct socket *so;
71 	int flag;
72 {
73 
74 	if (flag & FREAD) {
75 		if (soreadable(so))
76 			return (1);
77 		sbselqueue(&so->so_rcv);
78 	}
79 	if (flag & FWRITE) {
80 		if (sowriteable(so))
81 			return (1);
82 		sbselqueue(&so->so_snd);
83 	}
84 	return (0);
85 }
86 
87 /*
88  * Queue a process for a select on a socket buffer.
89  */
90 sbselqueue(sb)
91 	struct sockbuf *sb;
92 {
93 	register struct proc *p;
94 
95 	if ((p = sb->sb_sel) && p->p_wchan == (caddr_t)select)
96 		sb->sb_flags |= SB_COLL;
97 	else
98 		sb->sb_sel = u.u_procp;
99 }
100 
101 /*
102  * Wakeup processes waiting on a socket buffer.
103  */
104 sbwakeup(sb)
105 	struct sockbuf *sb;
106 {
107 
108 	if (sb->sb_sel) {
109 		selwakeup(sb->sb_sel, sb->sb_flags & SB_COLL);
110 		sb->sb_sel = 0;
111 		sb->sb_flags &= ~SB_COLL;
112 	}
113 	if (sb->sb_flags & SB_WAIT) {
114 		sb->sb_flags &= ~SB_WAIT;
115 		wakeup((caddr_t)sb->sb_cc);
116 	}
117 }
118 
119 /*
120  * Allot mbufs to a sockbuf.
121  */
122 sbreserve(sb, cc)
123 	struct sockbuf *sb;
124 {
125 
126 	if (m_reserve(cc) == 0)
127 		return (0);
128 	sb->sb_cc = cc;
129 	sb->sb_mbcnt = (cc*2)/MSIZE;
130 }
131 
132 /*
133  * Free mbufs held by a socket, and reserved mbuf space.
134  */
135 sbrelease(sb)
136 	struct sockbuf *sb;
137 {
138 
139 	sbflush(sb);
140 	m_release(sb->sb_cc);
141 	sb->sb_cc = sb->sb_mbcnt = 0;
142 }
143 
144 /*
145  * Routines to add (at the end) and remove (from the beginning)
146  * data from a mbuf queue.
147  */
148 
149 /*
150  * Append mbuf queue m to sockbuf sb.
151  */
152 sbappend(sb, m)
153 	register struct mbuf *m;
154 	register struct sockbuf *sb;
155 {
156 	register struct mbuf **np, *n;
157 
158 	np = &sb->sb_mb;
159 	while ((n = *np) && n->m_next)
160 		np = &n->m_next;
161 	while (m) {
162 		if (n && n->m_off <= MMAXOFF && m->m_off <= MMAXOFF &&
163 		   (int)n->m_act == 0 && (int)m->m_act == 0 &&
164 		   (n->m_off + n->m_len + m->m_off) <= MMAXOFF) {
165 			bcopy(mtod(m, caddr_t), mtod(n, caddr_t), m->m_len);
166 			n->m_len += m->m_len;
167 			sb->sb_cc += m->m_len;
168 			m = m_free(m);
169 			continue;
170 		}
171 		sballoc(sb, m);
172 		*np = m;
173 		n = m;
174 		np = &n->m_next;
175 		m = m->m_next;
176 	}
177 }
178 
179 /*
180  * Free all mbufs on a sockbuf mbuf chain.
181  * Check that resource allocations return to 0.
182  */
183 sbflush(sb)
184 	struct sockbuf *sb;
185 {
186 
187 	if (sb->sb_flags & SB_LOCK)
188 		panic("sbflush");
189 	sbdrop(sb, sb->sb_cc);
190 	if (sb->sb_cc || sb->sb_mbcnt || sb->sb_mb)
191 		panic("sbflush 2");
192 }
193 
194 /*
195  * Drop data from (the front of) a sockbuf chain.
196  */
197 sbdrop(sb, len)
198 	register struct sockbuf *sb;
199 	register int len;
200 {
201 	register struct mbuf *m = sb->sb_mb, *mn;
202 
203 	while (len > 0) {
204 		if (m == 0)
205 			panic("sbdrop");
206 		if (m->m_len <= len) {
207 			len -= m->m_len;
208 			sbfree(sb, m);
209 			MFREE(m, mn);
210 			m = mn;
211 		} else {
212 			m->m_len -= len;
213 			m->m_off += len;
214 			sb->sb_cc -= len;
215 			break;
216 		}
217 	}
218 	sb->sb_mb = m;
219 }
220 
221 struct mbuf *
222 sb_copy(sb, off, len)
223 	struct sockbuf *sb;
224 	int off;
225 	register int len;
226 {
227 	register struct mbuf *m, *n, **np;
228 	struct mbuf *top, *p;
229 COUNT(SB_COPY);
230 
231 	if (len == 0)
232 		return (0);
233 	if (off < 0 || len < 0)
234 		panic("sb_copy");
235 	m = sb->sb_mb;
236 	while (off > 0) {
237 		if (m == 0)
238 			panic("sb_copy");
239 		if (off < m->m_len)
240 			break;
241 		off -= m->m_len;
242 		m = m->m_next;
243 	}
244 	np = &top;
245 	top = 0;
246 	while (len > 0) {
247 		MGET(n, 1);
248 		*np = n;
249 		if (n == 0)
250 			goto nospace;
251 		if (m == 0)
252 			panic("sb_copy");
253 		n->m_len = MIN(len, m->m_len - off);
254 		if (m->m_off > MMAXOFF) {
255 			p = mtod(m, struct mbuf *);
256 			n->m_off = ((int)p - (int)n) + off;
257 			mprefcnt[mtopf(p)]++;
258 		} else {
259 			n->m_off = MMINOFF;
260 			bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
261 			    n->m_len);
262 		}
263 		len -= n->m_len;
264 		off = 0;
265 		m = m->m_next;
266 		np = &n->m_next;
267 	}
268 	return (top);
269 nospace:
270 	printf("snd_copy: no space\n");
271 	m_freem(top);
272 	return (0);
273 }
274