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