xref: /csrg-svn/sys/kern/uipc_socket.c (revision 4890)
1 /*	uipc_socket.c	4.3	81/11/14	*/
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  * Socket support routines.
22  *
23  * DEAL WITH INTERRUPT NOTIFICATION.
24  * DO NEWFD STUFF
25  */
26 
27 /*
28  * Create a socket.
29  */
30 socket(aso, type, iap, options)
31 	struct socket **aso;
32 	int type;
33 	register struct in_addr *iap;
34 	int options;
35 {
36 	register struct protosw *prp;
37 	register struct socket *so;
38 	struct mbuf *m;
39 	int pf, proto, error;
40 
41 	/*
42 	 * Use process standard protocol/protocol family if none
43 	 * specified by address argument.
44 	 */
45 	if (iap == 0) {
46 		pf = PF_INET;		/* should be u.u_protof */
47 		proto = 0;
48 	} else {
49 		pf = iap->ia_pf;
50 		proto = iap->ia_proto;
51 	}
52 
53 	/*
54 	 * If protocol specified, look for it, otherwise
55 	 * for a protocol of the correct type in the right family.
56 	 */
57 	if (proto)
58 		prp = pffindproto(pf, proto);
59 	else
60 		prp = pffindtype(pf, type);
61 	if (prp == 0)
62 		return (EPROTONOSUPPORT);
63 
64 	/*
65 	 * Get a socket structure.
66 	 */
67 	m = m_getclr(M_WAIT);
68 	if (m == 0)
69 		return (ENOBUFS);
70 	so = mtod(m, struct socket *);
71 	so->so_options = options;
72 
73 	/*
74 	 * Attach protocol to socket, initializing
75 	 * and reserving resources.
76 	 */
77 	so->so_proto = prp;
78 	(*prp->pr_usrreq)(so, PRU_ATTACH, 0, 0);
79 	if (so->so_error) {
80 /*###80 [cc] operands of = have incompatible types %%%*/
81 /*###80 [cc] zerosocket undefined %%%*/
82 		error = so->so_error;
83 		m_free(dtom(so));
84 		return (error);
85 	}
86 	*aso = so;
87 	return (0);
88 }
89 
90 /*
91  * Close a socket on last file table reference removal.
92  * Initiate disconnect if connected.
93  * Free socket when disconnect complete.
94  */
95 soclose(so)
96 	register struct socket *so;
97 {
98 	int s = splnet();		/* conservative */
99 
100 	if (so->so_pcb == 0)
101 		goto discard;
102 	if (so->so_state & SS_ISCONNECTED) {
103 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
104 			u.u_error = disconnect(so, 0);
105 			if (u.u_error) {
106 				splx(s);
107 				return;
108 			}
109 		}
110 		if ((so->so_state & SS_ISDISCONNECTING) &&
111 		    (so->so_options & SO_NBIO)) {
112 			u.u_error = EINPROGRESS;
113 			splx(s);
114 			return;
115 		}
116 		while (so->so_state & SS_ISCONNECTED)
117 			sleep((caddr_t)&so->so_timeo, PZERO+1);
118 	}
119 	u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0);
120 discard:
121 	if (so->so_pcb == 0)
122 		sofree(so);
123 	splx(s);
124 }
125 
126 sostat(so, sb)
127 	struct socket *so;
128 	struct stat *sb;
129 {
130 
131 	return (EOPNOTSUPP);
132 }
133 
134 /*
135  * Connect socket to a specified address.
136  * If already connected or connecting, then avoid
137  * the protocol entry, to keep its job simpler.
138  */
139 connect(so, iap)
140 	struct socket *so;
141 	struct in_addr *iap;
142 {
143 	int s = splnet();
144 	int error;
145 
146 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
147 		error = EISCONN;
148 		goto bad;
149 	}
150 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)iap);
151 bad:
152 	splx(s);
153 	return (error);
154 }
155 
156 /*
157  * Disconnect from a socket.
158  * Address parameter is from system call for later multicast
159  * protocols.  Check to make sure that connected and no disconnect
160  * in progress (for protocol's sake), and then invoke protocol.
161  */
162 disconnect(so, iap)
163 	struct socket *so;
164 	struct in_addr *iap;
165 {
166 	int s = splnet();
167 	int error;
168 
169 	if ((so->so_state & SS_ISCONNECTED) == 0) {
170 		error = ENOTCONN;
171 		goto bad;
172 	}
173 	if (so->so_state & SS_ISDISCONNECTING) {
174 		error = EALREADY;
175 		goto bad;
176 	}
177 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, 0);
178 bad:
179 	splx(s);
180 	return (error);
181 }
182 
183 /*
184  * Send on a socket.
185  * If send must go all at once and message is larger than
186  * send buffering, then hard error.
187  * Lock against other senders.
188  * If must go all at once and not enough room now, then
189  * inform user that this would block and do nothing.
190  */
191 send(so, iap)
192 	register struct socket *so;
193 	struct in_addr *iap;
194 {
195 	struct mbuf *top = 0;
196 	register struct mbuf *m, **mp = ⊤
197 	register int bufs;
198 	register int len;
199 	int error = 0;
200 	int s;
201 
202 	if (so->so_state & SS_CANTSENDMORE)
203 		return (EPIPE);
204 	if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat)
205 		return (EMSGSIZE);
206 	if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NBIO))
207 		return (EWOULDBLOCK);
208 	sblock(&so->so_snd);
209 #define	snderr(errno)	{ error = errno; splx(s); goto release; }
210 
211 	s = splnet();
212 again:
213 	if ((so->so_state & SS_ISCONNECTED) == 0) {
214 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
215 			snderr(ENOTCONN);
216 		if (iap == 0)
217 			snderr(EDESTADDRREQ);
218 	}
219 	if (so->so_error)
220 		snderr(so->so_error);
221 	if (top) {
222 		error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, iap);
223 		if (error) {
224 			splx(s);
225 			goto release;
226 		}
227 		top = 0;
228 		mp = ⊤
229 	}
230 	if (sosendallatonce(so) && sbspace(&so->so_snd) < u.u_count) {
231 		if (so->so_options & SO_NBIO)
232 			snderr(EWOULDBLOCK);
233 		sbunlock(&so->so_snd);
234 		sbwait(&so->so_snd);
235 		splx(s);
236 		goto again;
237 	}
238 	splx(s);
239 	while (u.u_count > 0 && sbspace(&so->so_snd) > 0) {
240 		MGET(m, 1);
241 		if (m == NULL) {
242 			error = ENOBUFS;
243 			m_freem(top);
244 			goto release;
245 		}
246 		if (u.u_count >= PGSIZE && bufs >= NMBPG) {
247 			register struct mbuf *p;
248 			MPGET(p, 1);
249 			if (p == 0)
250 				goto nopages;
251 			m->m_off = (int)p - (int)m;
252 			len = PGSIZE;
253 		} else {
254 nopages:
255 			m->m_off = MMINOFF;
256 			len = MIN(MLEN, u.u_count);
257 		}
258 		iomove(mtod(m, caddr_t), len, B_WRITE);
259 		m->m_len = len;
260 		*mp = m;
261 		mp = &m->m_next;
262 	}
263 	s = splnet();
264 	goto again;
265 
266 release:
267 	sbunlock(&so->so_snd);
268 	return (error);
269 }
270 
271 receive(so, iap)
272 	register struct socket *so;
273 	struct in_addr *iap;
274 {
275 	register struct mbuf *m, *n;
276 	register int len;
277 	int eor, s, error = 0;
278 
279 restart:
280 	sblock(&so->so_rcv);
281 	s = splnet();
282 
283 #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
284 	if (so->so_rcv.sb_cc == 0) {
285 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
286 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
287 			rcverr(ENOTCONN);
288 		if (so->so_state & SS_CANTRCVMORE) {
289 			splx(s);
290 			goto release;
291 		}
292 		if (so->so_options & SO_NBIO)
293 			rcverr(EWOULDBLOCK);
294 		sbunlock(&so->so_rcv);
295 		sleep((caddr_t)&so->so_rcv.sb_cc, PZERO+1);
296 		goto restart;
297 	}
298 	m = so->so_rcv.sb_mb;
299 	if (m == 0)
300 		panic("receive");
301 
302 	/*
303 	 * Pull address off receive chain, if protocol
304 	 * put one there.
305 	 */
306 	if ((so->so_proto->pr_flags & PR_ADDR)) {
307 		so->so_rcv.sb_mb = m->m_next;
308 		if (iap) {
309 			so->so_rcv.sb_cc -= m->m_len;
310 			len = MIN(m->m_len, sizeof (struct in_addr));
311 			bcopy(mtod(m, caddr_t), (caddr_t)iap, len);
312 		} else
313 			*iap = zeroin_addr;
314 		m = so->so_rcv.sb_mb;
315 		if (m == 0)
316 			panic("receive 2");
317 	}
318 
319 	/*
320 	 * Next pull data off the chain.
321 	 * Stop at eor or when run out of space in user buffer.
322 	 */
323 	eor = 0;
324 	do {
325 		len = MIN(m->m_len, u.u_count);
326 		if (len == m->m_len) {
327 			eor = (int)m->m_act;
328 			sbfree(&so->so_rcv, m);
329 		}
330 		splx(s);
331 		iomove(mtod(m, caddr_t), len, B_READ);
332 		s = splnet();
333 		if (len == m->m_len) {
334 			MFREE(m, n);
335 		} else {
336 			m->m_off += len;
337 			m->m_len -= len;
338 			so->so_rcv.sb_cc -= len;
339 		}
340 	} while ((m = so->so_rcv.sb_mb) && u.u_count && !eor);
341 
342 	/*
343 	 * If atomic protocol discard rest of record.
344 	 */
345 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
346 		do {
347 			if (m == 0)
348 				panic("receive 3");
349 			sbfree(&so->so_rcv, m);
350 			eor = (int)m->m_act;
351 			so->so_rcv.sb_mb = m->m_next;
352 			MFREE(m, n);
353 			m = n;
354 		} while (eor == 0);
355 
356 	/*
357 	 * If protocol cares, inform it that
358 	 * there is more space in the receive buffer.
359 	 */
360 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
361 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
362 
363 release:
364 	sounlock(&so->so_rcv);
365 	splx(s);
366 }
367 
368 skioctl(so, cmd, cmdp)
369 	register struct socket *so;
370 	int cmd;
371 	register caddr_t cmdp;
372 {
373 
374 	switch (cmdp) {
375 
376 	}
377 	switch (so->so_type) {
378 
379 	case SOCK_STREAM:
380 		break;
381 
382 	case SOCK_DGRAM:
383 		break;
384 
385 	case SOCK_RDM:
386 		break;
387 
388 	case SOCK_RAW:
389 		break;
390 
391 	}
392 }
393 /*###417 [cc] operands of = have incompatible types %%%*/
394 /*###417 [cc] zeroin_addr undefined %%%*/
395