xref: /csrg-svn/sys/kern/uipc_socket.c (revision 5358)
1 /*	uipc_socket.c	4.22	82/01/07	*/
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 	bzero((caddr_t)sb, sizeof (*sb));		/* XXX */
163 	return (0);					/* XXX */
164 }
165 
166 /*
167  * Accept connection on a socket.
168  */
169 soaccept(so, asa)
170 	struct socket *so;
171 	struct sockaddr *asa;
172 {
173 	int s = splnet();
174 	int error;
175 
176 COUNT(SOACCEPT);
177 	if ((so->so_options & SO_ACCEPTCONN) == 0) {
178 		error = EINVAL;			/* XXX */
179 		goto bad;
180 	}
181 	if ((so->so_state & SS_CONNAWAITING) == 0) {
182 		error = ENOTCONN;
183 		goto bad;
184 	}
185 	so->so_state &= ~SS_CONNAWAITING;
186 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa);
187 bad:
188 	splx(s);
189 	return (error);
190 }
191 
192 /*
193  * Connect socket to a specified address.
194  * If already connected or connecting, then avoid
195  * the protocol entry, to keep its job simpler.
196  */
197 soconnect(so, asa)
198 	struct socket *so;
199 	struct sockaddr *asa;
200 {
201 	int s = splnet();
202 	int error;
203 
204 COUNT(SOCONNECT);
205 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
206 		error = EISCONN;
207 		goto bad;
208 	}
209 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa);
210 bad:
211 	splx(s);
212 	return (error);
213 }
214 
215 /*
216  * Disconnect from a socket.
217  * Address parameter is from system call for later multicast
218  * protocols.  Check to make sure that connected and no disconnect
219  * in progress (for protocol's sake), and then invoke protocol.
220  */
221 sodisconnect(so, asa)
222 	struct socket *so;
223 	struct sockaddr *asa;
224 {
225 	int s = splnet();
226 	int error;
227 
228 COUNT(SODISCONNECT);
229 	if ((so->so_state & SS_ISCONNECTED) == 0) {
230 		error = ENOTCONN;
231 		goto bad;
232 	}
233 	if (so->so_state & SS_ISDISCONNECTING) {
234 		error = EALREADY;
235 		goto bad;
236 	}
237 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa);
238 bad:
239 	splx(s);
240 	return (error);
241 }
242 
243 /*
244  * Send on a socket.
245  * If send must go all at once and message is larger than
246  * send buffering, then hard error.
247  * Lock against other senders.
248  * If must go all at once and not enough room now, then
249  * inform user that this would block and do nothing.
250  */
251 sosend(so, asa)
252 	register struct socket *so;
253 	struct sockaddr *asa;
254 {
255 	struct mbuf *top = 0;
256 	register struct mbuf *m, **mp = ⊤
257 	register u_int len;
258 	int error = 0, space, s;
259 
260 COUNT(SOSEND);
261 	if (so->so_state & SS_CANTSENDMORE)
262 		return (EPIPE);
263 	if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat)
264 		return (EMSGSIZE);
265 	if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NBIO))
266 		return (EWOULDBLOCK);
267 	sblock(&so->so_snd);
268 #define	snderr(errno)	{ error = errno; splx(s); goto release; }
269 
270 	s = splnet();
271 again:
272 	if (so->so_error) {
273 		error = so->so_error;
274 		so->so_error = 0;
275 		splx(s);
276 		goto release;
277 	}
278 	if ((so->so_state & SS_ISCONNECTED) == 0) {
279 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
280 			snderr(ENOTCONN);
281 		if (asa == 0)
282 			snderr(EDESTADDRREQ);
283 	}
284 	if (top) {
285 		error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa);
286 		if (error) {
287 			splx(s);
288 			goto release;
289 		}
290 		top = 0;
291 		mp = ⊤
292 	}
293 	if (u.u_count == 0) {
294 		splx(s);
295 		goto release;
296 	}
297 	space = sbspace(&so->so_snd);
298 	if (space == 0 || sosendallatonce(so) && space < u.u_count) {
299 		if (so->so_options & SO_NBIO)
300 			snderr(EWOULDBLOCK);
301 		sbunlock(&so->so_snd);
302 		sbwait(&so->so_snd);
303 		splx(s);
304 		goto again;
305 	}
306 	splx(s);
307 	while (u.u_count && space > 0) {
308 		MGET(m, 1);
309 		if (m == NULL) {
310 			error = ENOBUFS;
311 			m_freem(top);
312 			goto release;
313 		}
314 		if (u.u_count >= CLBYTES && space >= CLBYTES) {
315 			register struct mbuf *p;
316 			MCLGET(p, 1);
317 			if (p == 0)
318 				goto nopages;
319 			m->m_off = (int)p - (int)m;
320 			len = CLBYTES;
321 		} else {
322 nopages:
323 			m->m_off = MMINOFF;
324 			len = MIN(MLEN, u.u_count);
325 		}
326 		iomove(mtod(m, caddr_t), len, B_WRITE);
327 		m->m_len = len;
328 		*mp = m;
329 		mp = &m->m_next;
330 		space = sbspace(&so->so_snd);
331 	}
332 	s = splnet();
333 	goto again;
334 
335 release:
336 	sbunlock(&so->so_snd);
337 	return (error);
338 }
339 
340 soreceive(so, asa)
341 	register struct socket *so;
342 	struct sockaddr *asa;
343 {
344 	register struct mbuf *m, *n;
345 	u_int len;
346 	int eor, s, error = 0;
347 
348 COUNT(SORECEIVE);
349 restart:
350 	sblock(&so->so_rcv);
351 	s = splnet();
352 
353 #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
354 	if (so->so_rcv.sb_cc == 0) {
355 		if (so->so_error) {
356 			error = so->so_error;
357 			so->so_error = 0;
358 			splx(s);
359 			goto release;
360 		}
361 		if (so->so_state & SS_CANTRCVMORE) {
362 			splx(s);
363 			goto release;
364 		}
365 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
366 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
367 			rcverr(ENOTCONN);
368 		if (so->so_options & SO_NBIO)
369 			rcverr(EWOULDBLOCK);
370 		sbunlock(&so->so_rcv);
371 		sbwait(&so->so_rcv);
372 		splx(s);
373 		goto restart;
374 	}
375 	m = so->so_rcv.sb_mb;
376 	if (m == 0)
377 		panic("receive");
378 	if (so->so_proto->pr_flags & PR_ADDR) {
379 		if (m->m_len != sizeof (struct sockaddr))
380 			panic("soreceive addr");
381 		if (asa)
382 			bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa));
383 		so->so_rcv.sb_cc -= m->m_len;
384 		so->so_rcv.sb_mbcnt -= MSIZE;
385 		m = m_free(m);
386 		if (m == 0)
387 			panic("receive 2");
388 		so->so_rcv.sb_mb = m;
389 	}
390 	eor = 0;
391 	do {
392 		len = MIN(m->m_len, u.u_count);
393 		if (len == m->m_len) {
394 			eor = (int)m->m_act;
395 			sbfree(&so->so_rcv, m);
396 			so->so_rcv.sb_mb = m->m_next;
397 		}
398 		splx(s);
399 		iomove(mtod(m, caddr_t), len, B_READ);
400 		s = splnet();
401 		if (len == m->m_len) {
402 			MFREE(m, n);
403 		} else {
404 			m->m_off += len;
405 			m->m_len -= len;
406 			so->so_rcv.sb_cc -= len;
407 		}
408 	} while ((m = so->so_rcv.sb_mb) && u.u_count && !eor);
409 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
410 		do {
411 			if (m == 0)
412 				panic("receive 3");
413 			sbfree(&so->so_rcv, m);
414 			eor = (int)m->m_act;
415 			so->so_rcv.sb_mb = m->m_next;
416 			MFREE(m, n);
417 			m = n;
418 		} while (eor == 0);
419 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
420 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
421 release:
422 	sbunlock(&so->so_rcv);
423 	splx(s);
424 	return (error);
425 }
426 
427 /*ARGSUSED*/
428 soioctl(so, cmd, cmdp)
429 	register struct socket *so;
430 	int cmd;
431 	register caddr_t cmdp;
432 {
433 
434 COUNT(SOIOCTL);
435 	switch (cmd) {
436 
437 	case SIOCDONE: {
438 		int flags;
439 		if (copyin(cmdp, (caddr_t)&flags, sizeof (flags))) {
440 			u.u_error = EFAULT;
441 			return;
442 		}
443 		if (flags & FREAD) {
444 			int s = splimp();
445 			socantrcvmore(so);
446 			sbflush(&so->so_rcv);
447 		}
448 		if (flags & FWRITE)
449 			u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, (struct mbuf *)0, 0);
450 		return;
451 	}
452 
453 	}
454 	switch (so->so_type) {
455 
456 	case SOCK_STREAM:
457 		break;
458 
459 	case SOCK_DGRAM:
460 		break;
461 
462 	case SOCK_RDM:
463 		break;
464 
465 	case SOCK_RAW:
466 		break;
467 
468 	}
469 }
470