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