xref: /csrg-svn/sys/kern/uipc_socket2.c (revision 5015)
1 /*	uipc_socket2.c	4.6	81/11/21	*/
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)/MSIZE;
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);
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_off) <= MMAXOFF) {
194 			bcopy(mtod(m, caddr_t), mtod(n, caddr_t),
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 	for (m = m0; m; m = m->m_next)
219 		len += m->m_len;
220 	if (len > sbspace(sb))
221 		return (0);
222 	m = m_get(0);
223 	if (m == 0)
224 		return (0);
225 	m->m_off = MMINOFF;
226 	m->m_len = sizeof (struct sockaddr);
227 	msa = mtod(m, struct sockaddr *);
228 	*msa = *asa;
229 	m->m_act = (struct mbuf *)1;
230 	sbappend(sb, m);
231 	m0->m_act = (struct mbuf *)1;
232 	sbappend(sb, m0);
233 	return (1);
234 }
235 
236 /*
237  * Free all mbufs on a sockbuf mbuf chain.
238  * Check that resource allocations return to 0.
239  */
240 sbflush(sb)
241 	struct sockbuf *sb;
242 {
243 
244 	if (sb->sb_flags & SB_LOCK)
245 		panic("sbflush");
246 	sbdrop(sb, sb->sb_cc);
247 	if (sb->sb_cc || sb->sb_mbcnt || sb->sb_mb)
248 		panic("sbflush 2");
249 }
250 
251 /*
252  * Drop data from (the front of) a sockbuf chain.
253  */
254 sbdrop(sb, len)
255 	register struct sockbuf *sb;
256 	register int len;
257 {
258 	register struct mbuf *m = sb->sb_mb, *mn;
259 
260 	while (len > 0) {
261 		if (m == 0)
262 			panic("sbdrop");
263 		if (m->m_len <= len) {
264 			len -= m->m_len;
265 			sbfree(sb, m);
266 			MFREE(m, mn);
267 			m = mn;
268 		} else {
269 			m->m_len -= len;
270 			m->m_off += len;
271 			sb->sb_cc -= len;
272 			break;
273 		}
274 	}
275 	sb->sb_mb = m;
276 }
277