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