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