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