xref: /csrg-svn/sys/kern/uipc_socket.c (revision 5281)
1 /*	uipc_socket.c	4.20	81/12/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 "../h/stat.h"
16 #include "../h/ioctl.h"
17 #include "../net/in.h"
18 #include "../net/in_systm.h"
19 
20 /*
21  * Socket support routines.
22  *
23  * DEAL WITH INTERRUPT NOTIFICATION.
24  */
25 
26 /*
27  * Create a socket.
28  */
29 socreate(aso, type, asp, asa, options)
30 	struct socket **aso;
31 	int type;
32 	struct sockproto *asp;
33 	struct sockaddr *asa;
34 	int options;
35 {
36 	register struct protosw *prp;
37 	register struct socket *so;
38 	struct mbuf *m;
39 	int pf, proto, error;
40 COUNT(SOCREATE);
41 
42 	/*
43 	 * Use process standard protocol/protocol family if none
44 	 * specified by address argument.
45 	 */
46 	if (asp == 0) {
47 		pf = PF_INET;		/* should be u.u_protof */
48 		proto = 0;
49 	} else {
50 		pf = asp->sp_family;
51 		proto = asp->sp_protocol;
52 	}
53 
54 	/*
55 	 * If protocol specified, look for it, otherwise
56 	 * for a protocol of the correct type in the right family.
57 	 */
58 	if (proto)
59 		prp = pffindproto(pf, proto);
60 	else
61 		prp = pffindtype(pf, type);
62 	if (prp == 0)
63 		return (EPROTONOSUPPORT);
64 
65 	/*
66 	 * Get a socket structure.
67 	 */
68 	m = m_getclr(M_WAIT);
69 	if (m == 0)
70 		return (ENOBUFS);
71 	so = mtod(m, struct socket *);
72 	so->so_options = options;
73 
74 	/*
75 	 * Attach protocol to socket, initializing
76 	 * and reserving resources.
77 	 */
78 	so->so_proto = prp;
79 	error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa);
80 	if (error) {
81 		(void) m_free(dtom(so));
82 		return (error);
83 	}
84 	*aso = so;
85 	return (0);
86 }
87 
88 sofree(so)
89 	struct socket *so;
90 {
91 
92 COUNT(SOFREE);
93 	if (so->so_pcb || (so->so_state & SS_USERGONE) == 0)
94 		return;
95 	sbrelease(&so->so_snd);
96 	sbrelease(&so->so_rcv);
97 	(void) m_free(dtom(so));
98 }
99 
100 /*
101  * Close a socket on last file table reference removal.
102  * Initiate disconnect if connected.
103  * Free socket when disconnect complete.
104  */
105 soclose(so)
106 	register struct socket *so;
107 {
108 	int s = splnet();		/* conservative */
109 
110 COUNT(SOCLOSE);
111 	if (so->so_pcb == 0)
112 		goto discard;
113 	if (so->so_state & SS_ISCONNECTED) {
114 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
115 			u.u_error = sodisconnect(so, (struct sockaddr *)0);
116 			if (u.u_error) {
117 				splx(s);
118 				return;
119 			}
120 		}
121 		if (so->so_options & SO_LETDATADRAIN) {
122 			if ((so->so_state & SS_ISDISCONNECTING) &&
123 			    (so->so_options & SO_NBIO)) {
124 				u.u_error = EINPROGRESS;
125 				splx(s);
126 				return;
127 			}
128 			while (so->so_state & SS_ISCONNECTED)
129 				sleep((caddr_t)&so->so_timeo, PZERO+1);
130 		}
131 	}
132 	u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0);
133 discard:
134 	so->so_state |= SS_USERGONE;
135 	sofree(so);
136 	splx(s);
137 }
138 
139 sosplice(pso, so)
140 	struct socket *pso, *so;
141 {
142 
143 COUNT(SOSPLICE);
144 	if (pso->so_proto->pr_family != PF_UNIX) {
145 		struct socket *tso;
146 		tso = pso; pso = so; so = tso;
147 	}
148 	if (pso->so_proto->pr_family != PF_UNIX)
149 		return (EOPNOTSUPP);
150 	/* check types and buffer space */
151 	/* merge buffers */
152 	return (0);
153 }
154 
155 /*ARGSUSED*/
156 sostat(so, sb)
157 	struct socket *so;
158 	struct stat *sb;
159 {
160 
161 COUNT(SOSTAT);
162 	return (EOPNOTSUPP);
163 }
164 
165 /*
166  * Accept connection on a socket.
167  */
168 soaccept(so, asa)
169 	struct socket *so;
170 	struct sockaddr *asa;
171 {
172 	int s = splnet();
173 	int error;
174 
175 COUNT(SOACCEPT);
176 	if ((so->so_options & SO_ACCEPTCONN) == 0) {
177 		error = EINVAL;			/* XXX */
178 		goto bad;
179 	}
180 	if ((so->so_state & SS_CONNAWAITING) == 0) {
181 		error = ENOTCONN;
182 		goto bad;
183 	}
184 	so->so_state &= ~SS_CONNAWAITING;
185 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa);
186 bad:
187 	splx(s);
188 	return (error);
189 }
190 
191 /*
192  * Connect socket to a specified address.
193  * If already connected or connecting, then avoid
194  * the protocol entry, to keep its job simpler.
195  */
196 soconnect(so, asa)
197 	struct socket *so;
198 	struct sockaddr *asa;
199 {
200 	int s = splnet();
201 	int error;
202 
203 COUNT(SOCONNECT);
204 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
205 		error = EISCONN;
206 		goto bad;
207 	}
208 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa);
209 bad:
210 	splx(s);
211 	return (error);
212 }
213 
214 /*
215  * Disconnect from a socket.
216  * Address parameter is from system call for later multicast
217  * protocols.  Check to make sure that connected and no disconnect
218  * in progress (for protocol's sake), and then invoke protocol.
219  */
220 sodisconnect(so, asa)
221 	struct socket *so;
222 	struct sockaddr *asa;
223 {
224 	int s = splnet();
225 	int error;
226 
227 COUNT(SODISCONNECT);
228 	if ((so->so_state & SS_ISCONNECTED) == 0) {
229 		error = ENOTCONN;
230 		goto bad;
231 	}
232 	if (so->so_state & SS_ISDISCONNECTING) {
233 		error = EALREADY;
234 		goto bad;
235 	}
236 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa);
237 bad:
238 	splx(s);
239 	return (error);
240 }
241 
242 /*
243  * Send on a socket.
244  * If send must go all at once and message is larger than
245  * send buffering, then hard error.
246  * Lock against other senders.
247  * If must go all at once and not enough room now, then
248  * inform user that this would block and do nothing.
249  */
250 sosend(so, asa)
251 	register struct socket *so;
252 	struct sockaddr *asa;
253 {
254 	struct mbuf *top = 0;
255 	register struct mbuf *m, **mp = ⊤
256 	register u_int len;
257 	int error = 0, space, s;
258 
259 COUNT(SOSEND);
260 	if (so->so_state & SS_CANTSENDMORE)
261 		return (EPIPE);
262 	if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat)
263 		return (EMSGSIZE);
264 	if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NBIO))
265 		return (EWOULDBLOCK);
266 	sblock(&so->so_snd);
267 #define	snderr(errno)	{ error = errno; splx(s); goto release; }
268 
269 	s = splnet();
270 again:
271 	if (so->so_error) {
272 		error = so->so_error;
273 		so->so_error = 0;
274 		splx(s);
275 		goto release;
276 	}
277 	if ((so->so_state & SS_ISCONNECTED) == 0) {
278 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
279 			snderr(ENOTCONN);
280 		if (asa == 0)
281 			snderr(EDESTADDRREQ);
282 	}
283 	if (top) {
284 		error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa);
285 		if (error) {
286 			splx(s);
287 			goto release;
288 		}
289 		top = 0;
290 		mp = ⊤
291 	}
292 	if (u.u_count == 0) {
293 		splx(s);
294 		goto release;
295 	}
296 	space = sbspace(&so->so_snd);
297 	if (space == 0 || sosendallatonce(so) && space < u.u_count) {
298 		if (so->so_options & SO_NBIO)
299 			snderr(EWOULDBLOCK);
300 		sbunlock(&so->so_snd);
301 		sbwait(&so->so_snd);
302 		splx(s);
303 		goto again;
304 	}
305 	splx(s);
306 	while (u.u_count && space > 0) {
307 		MGET(m, 1);
308 		if (m == NULL) {
309 			error = ENOBUFS;
310 			m_freem(top);
311 			goto release;
312 		}
313 		if (u.u_count >= CLBYTES && space >= CLBYTES) {
314 			register struct mbuf *p;
315 			MCLGET(p, 1);
316 			if (p == 0)
317 				goto nopages;
318 			m->m_off = (int)p - (int)m;
319 			len = CLBYTES;
320 		} else {
321 nopages:
322 			m->m_off = MMINOFF;
323 			len = MIN(MLEN, u.u_count);
324 		}
325 		iomove(mtod(m, caddr_t), len, B_WRITE);
326 		m->m_len = len;
327 		*mp = m;
328 		mp = &m->m_next;
329 		space = sbspace(&so->so_snd);
330 	}
331 	s = splnet();
332 	goto again;
333 
334 release:
335 	sbunlock(&so->so_snd);
336 	return (error);
337 }
338 
339 soreceive(so, asa)
340 	register struct socket *so;
341 	struct sockaddr *asa;
342 {
343 	register struct mbuf *m, *n;
344 	u_int len;
345 	int eor, s, error = 0;
346 
347 COUNT(SORECEIVE);
348 restart:
349 	sblock(&so->so_rcv);
350 	s = splnet();
351 
352 #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
353 	if (so->so_rcv.sb_cc == 0) {
354 		if (so->so_error) {
355 			error = so->so_error;
356 			so->so_error = 0;
357 			splx(s);
358 			goto release;
359 		}
360 		if (so->so_state & SS_CANTRCVMORE) {
361 			splx(s);
362 			goto release;
363 		}
364 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
365 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
366 			rcverr(ENOTCONN);
367 		if (so->so_options & SO_NBIO)
368 			rcverr(EWOULDBLOCK);
369 		sbunlock(&so->so_rcv);
370 		sbwait(&so->so_rcv);
371 		splx(s);
372 		goto restart;
373 	}
374 	m = so->so_rcv.sb_mb;
375 	if (m == 0)
376 		panic("receive");
377 	if (so->so_proto->pr_flags & PR_ADDR) {
378 		if (m->m_len != sizeof (struct sockaddr))
379 			panic("soreceive addr");
380 		if (asa)
381 			bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa));
382 		so->so_rcv.sb_cc -= m->m_len;
383 		so->so_rcv.sb_mbcnt -= MSIZE;
384 		m = m_free(m);
385 		if (m == 0)
386 			panic("receive 2");
387 		so->so_rcv.sb_mb = m;
388 	}
389 	eor = 0;
390 	do {
391 		len = MIN(m->m_len, u.u_count);
392 		if (len == m->m_len) {
393 			eor = (int)m->m_act;
394 			sbfree(&so->so_rcv, m);
395 		}
396 		splx(s);
397 		iomove(mtod(m, caddr_t), len, B_READ);
398 		s = splnet();
399 		if (len == m->m_len) {
400 			MFREE(m, n);
401 			so->so_rcv.sb_mb = n;
402 		} else {
403 			m->m_off += len;
404 			m->m_len -= len;
405 			so->so_rcv.sb_cc -= len;
406 		}
407 	} while ((m = so->so_rcv.sb_mb) && u.u_count && !eor);
408 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
409 		do {
410 			if (m == 0)
411 				panic("receive 3");
412 			sbfree(&so->so_rcv, m);
413 			eor = (int)m->m_act;
414 			so->so_rcv.sb_mb = m->m_next;
415 			MFREE(m, n);
416 			m = n;
417 		} while (eor == 0);
418 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
419 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
420 release:
421 	sbunlock(&so->so_rcv);
422 	splx(s);
423 	return (error);
424 }
425 
426 /*ARGSUSED*/
427 soioctl(so, cmd, cmdp)
428 	register struct socket *so;
429 	int cmd;
430 	register caddr_t cmdp;
431 {
432 
433 COUNT(SOIOCTL);
434 	switch (cmdp) {
435 
436 	case SIOCDONE: {
437 		int flags;
438 		if (copyin(cmdp, (caddr_t)&flags, sizeof (flags))) {
439 			u.u_error = EFAULT;
440 			return;
441 		}
442 		if (flags & FREAD) {
443 			int s = splimp();
444 			socantrcvmore(so);
445 			sbflush(&so->so_rcv);
446 		}
447 		if (flags & FWRITE)
448 			(*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, (struct mbuf *)0, 0);
449 		return;
450 	}
451 
452 	}
453 	switch (so->so_type) {
454 
455 	case SOCK_STREAM:
456 		break;
457 
458 	case SOCK_DGRAM:
459 		break;
460 
461 	case SOCK_RDM:
462 		break;
463 
464 	case SOCK_RAW:
465 		break;
466 
467 	}
468 }
469