fix to way send looks at space: sleep when none!
[unix-history] / usr / src / sys / kern / uipc_socket.c
CommitLineData
50fc8df6 1/* uipc_socket.c 4.12 81/11/22 */
ce9d8eb4
BJ
2
3#include "../h/param.h"
92a533e6 4#include "../h/systm.h"
ce9d8eb4
BJ
5#include "../h/dir.h"
6#include "../h/user.h"
92a533e6
BJ
7#include "../h/proc.h"
8#include "../h/file.h"
ce9d8eb4 9#include "../h/inode.h"
92a533e6 10#include "../h/buf.h"
ce9d8eb4 11#include "../h/mbuf.h"
92a533e6
BJ
12#include "../h/protosw.h"
13#include "../h/socket.h"
14#include "../h/socketvar.h"
ae921915 15#include "../h/stat.h"
92a533e6
BJ
16#include "../net/inet.h"
17#include "../net/inet_systm.h"
ce9d8eb4 18
ce9d8eb4 19/*
cc15ab5d
BJ
20 * Socket support routines.
21 *
22 * DEAL WITH INTERRUPT NOTIFICATION.
ce9d8eb4 23 */
ce9d8eb4
BJ
24
25/*
26 * Create a socket.
27 */
2b4b57cd 28socreate(aso, type, asp, asa, options)
ce9d8eb4
BJ
29 struct socket **aso;
30 int type;
2b4b57cd
BJ
31 struct sockproto *asp;
32 struct sockaddr *asa;
92a533e6 33 int options;
ce9d8eb4
BJ
34{
35 register struct protosw *prp;
36 register struct socket *so;
37 struct mbuf *m;
cc15ab5d 38 int pf, proto, error;
2b4b57cd 39COUNT(SOCREATE);
ce9d8eb4
BJ
40
41 /*
cc15ab5d
BJ
42 * Use process standard protocol/protocol family if none
43 * specified by address argument.
ce9d8eb4 44 */
2b4b57cd 45 if (asp == 0) {
cc15ab5d 46 pf = PF_INET; /* should be u.u_protof */
ce9d8eb4
BJ
47 proto = 0;
48 } else {
2b4b57cd
BJ
49 pf = asp->sp_family;
50 proto = asp->sp_protocol;
ce9d8eb4 51 }
cc15ab5d
BJ
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);
ce9d8eb4
BJ
63
64 /*
65 * Get a socket structure.
66 */
cc15ab5d 67 m = m_getclr(M_WAIT);
ce9d8eb4
BJ
68 if (m == 0)
69 return (ENOBUFS);
ce9d8eb4 70 so = mtod(m, struct socket *);
92a533e6 71 so->so_options = options;
ce9d8eb4
BJ
72
73 /*
cc15ab5d
BJ
74 * Attach protocol to socket, initializing
75 * and reserving resources.
ce9d8eb4
BJ
76 */
77 so->so_proto = prp;
b91acce4
BJ
78 error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa);
79 if (error) {
2752c877 80 (void) m_free(dtom(so));
cc15ab5d 81 return (error);
ce9d8eb4
BJ
82 }
83 *aso = so;
84 return (0);
85}
86
ae921915
BJ
87sofree(so)
88 struct socket *so;
89{
90
2b4b57cd 91COUNT(SOFREE);
4ad99bae
BJ
92 if (so->so_pcb || (so->so_state & SS_USERGONE) == 0)
93 return;
94 sbrelease(&so->so_snd);
95 sbrelease(&so->so_rcv);
2752c877 96 (void) m_free(dtom(so));
ae921915
BJ
97}
98
92a533e6 99/*
cc15ab5d
BJ
100 * Close a socket on last file table reference removal.
101 * Initiate disconnect if connected.
102 * Free socket when disconnect complete.
92a533e6 103 */
cc15ab5d 104soclose(so)
92a533e6 105 register struct socket *so;
92a533e6 106{
cc15ab5d
BJ
107 int s = splnet(); /* conservative */
108
2b4b57cd 109COUNT(SOCLOSE);
cc15ab5d
BJ
110 if (so->so_pcb == 0)
111 goto discard;
112 if (so->so_state & SS_ISCONNECTED) {
113 if ((so->so_state & SS_ISDISCONNECTING) == 0) {
2b4b57cd 114 u.u_error = sodisconnect(so, (struct sockaddr *)0);
cc15ab5d
BJ
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);
130discard:
4ad99bae
BJ
131 so->so_state |= SS_USERGONE;
132 sofree(so);
cc15ab5d 133 splx(s);
92a533e6
BJ
134}
135
2b4b57cd
BJ
136sosplice(pso, so)
137 struct socket *pso, *so;
138{
139
140COUNT(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
ae921915 152/*ARGSUSED*/
cc15ab5d 153sostat(so, sb)
92a533e6 154 struct socket *so;
cc15ab5d 155 struct stat *sb;
92a533e6
BJ
156{
157
2b4b57cd 158COUNT(SOSTAT);
cc15ab5d 159 return (EOPNOTSUPP);
92a533e6
BJ
160}
161
2b4b57cd
BJ
162/*
163 * Accept connection on a socket.
164 */
165soaccept(so, asa)
166 struct socket *so;
167 struct sockaddr *asa;
168{
169 int s = splnet();
170 int error;
171
172COUNT(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);
182bad:
183 splx(s);
184 return (error);
185}
186
ce9d8eb4 187/*
cc15ab5d
BJ
188 * Connect socket to a specified address.
189 * If already connected or connecting, then avoid
190 * the protocol entry, to keep its job simpler.
ce9d8eb4 191 */
2b4b57cd 192soconnect(so, asa)
ce9d8eb4 193 struct socket *so;
2b4b57cd 194 struct sockaddr *asa;
ce9d8eb4 195{
cc15ab5d
BJ
196 int s = splnet();
197 int error;
ce9d8eb4 198
2b4b57cd 199COUNT(SOCONNECT);
cc15ab5d
BJ
200 if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
201 error = EISCONN;
202 goto bad;
203 }
2b4b57cd 204 error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa);
cc15ab5d
BJ
205bad:
206 splx(s);
207 return (error);
ce9d8eb4
BJ
208}
209
210/*
cc15ab5d
BJ
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.
ce9d8eb4 215 */
2b4b57cd 216sodisconnect(so, asa)
ce9d8eb4 217 struct socket *so;
2b4b57cd 218 struct sockaddr *asa;
ce9d8eb4 219{
cc15ab5d
BJ
220 int s = splnet();
221 int error;
ce9d8eb4 222
2b4b57cd 223COUNT(SODISCONNECT);
cc15ab5d
BJ
224 if ((so->so_state & SS_ISCONNECTED) == 0) {
225 error = ENOTCONN;
226 goto bad;
ce9d8eb4 227 }
cc15ab5d
BJ
228 if (so->so_state & SS_ISDISCONNECTING) {
229 error = EALREADY;
230 goto bad;
ce9d8eb4 231 }
2b4b57cd 232 error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa);
cc15ab5d
BJ
233bad:
234 splx(s);
235 return (error);
ce9d8eb4
BJ
236}
237
cc15ab5d
BJ
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 */
2b4b57cd 246sosend(so, asa)
ce9d8eb4 247 register struct socket *so;
2b4b57cd 248 struct sockaddr *asa;
ce9d8eb4 249{
cc15ab5d
BJ
250 struct mbuf *top = 0;
251 register struct mbuf *m, **mp = ⊤
ae921915
BJ
252 register u_int len;
253 int error = 0, space, s;
ce9d8eb4 254
2b4b57cd 255COUNT(SOSEND);
cc15ab5d
BJ
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();
266again:
267 if ((so->so_state & SS_ISCONNECTED) == 0) {
268 if (so->so_proto->pr_flags & PR_CONNREQUIRED)
269 snderr(ENOTCONN);
2b4b57cd 270 if (asa == 0)
cc15ab5d
BJ
271 snderr(EDESTADDRREQ);
272 }
273 if (so->so_error)
274 snderr(so->so_error);
275 if (top) {
2b4b57cd 276 error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa);
cc15ab5d
BJ
277 if (error) {
278 splx(s);
ce9d8eb4
BJ
279 goto release;
280 }
cc15ab5d
BJ
281 top = 0;
282 mp = ⊤
ce9d8eb4 283 }
b91acce4
BJ
284 if (u.u_count == 0) {
285 splx(s);
286 goto release;
287 }
50fc8df6
BJ
288 space = sbspace(&so->so_snd);
289 if (space == 0 || sosendallatonce(so) && space < u.u_count) {
cc15ab5d
BJ
290 if (so->so_options & SO_NBIO)
291 snderr(EWOULDBLOCK);
292 sbunlock(&so->so_snd);
293 sbwait(&so->so_snd);
294 splx(s);
ce9d8eb4
BJ
295 goto again;
296 }
cc15ab5d 297 splx(s);
50fc8df6 298 while (u.u_count && space > 0) {
cc15ab5d
BJ
299 MGET(m, 1);
300 if (m == NULL) {
301 error = ENOBUFS;
302 m_freem(top);
303 goto release;
ce9d8eb4 304 }
ae921915 305 if (u.u_count >= PGSIZE && space >= NMBPG) {
cc15ab5d
BJ
306 register struct mbuf *p;
307 MPGET(p, 1);
308 if (p == 0)
309 goto nopages;
310 m->m_off = (int)p - (int)m;
311 len = PGSIZE;
312 } else {
ce9d8eb4 313nopages:
cc15ab5d
BJ
314 m->m_off = MMINOFF;
315 len = MIN(MLEN, u.u_count);
ce9d8eb4 316 }
cc15ab5d
BJ
317 iomove(mtod(m, caddr_t), len, B_WRITE);
318 m->m_len = len;
319 *mp = m;
320 mp = &m->m_next;
50fc8df6 321 space = sbspace(&so->so_snd);
ce9d8eb4 322 }
cc15ab5d
BJ
323 s = splnet();
324 goto again;
325
ce9d8eb4 326release:
cc15ab5d 327 sbunlock(&so->so_snd);
ce9d8eb4
BJ
328 return (error);
329}
330
2b4b57cd 331soreceive(so, asa)
ce9d8eb4 332 register struct socket *so;
2b4b57cd 333 struct sockaddr *asa;
ce9d8eb4
BJ
334{
335 register struct mbuf *m, *n;
ae921915 336 u_int len;
cc15ab5d 337 int eor, s, error = 0;
ce9d8eb4 338
2b4b57cd 339COUNT(SORECEIVE);
cc15ab5d
BJ
340restart:
341 sblock(&so->so_rcv);
342 s = splnet();
343
344#define rcverr(errno) { error = errno; splx(s); goto release; }
ce9d8eb4 345 if (so->so_rcv.sb_cc == 0) {
cc15ab5d
BJ
346 if (so->so_state & SS_CANTRCVMORE) {
347 splx(s);
348 goto release;
349 }
196d84fd
BJ
350 if ((so->so_state & SS_ISCONNECTED) == 0 &&
351 (so->so_proto->pr_flags & PR_CONNREQUIRED))
352 rcverr(ENOTCONN);
cc15ab5d 353 if (so->so_options & SO_NBIO)
ae921915 354 rcverr (EWOULDBLOCK);
cc15ab5d 355 sbunlock(&so->so_rcv);
2752c877 356 sbwait(&so->so_rcv);
a4f6d93d 357 splx(s);
cc15ab5d 358 goto restart;
ce9d8eb4 359 }
92a533e6 360 m = so->so_rcv.sb_mb;
ce9d8eb4
BJ
361 if (m == 0)
362 panic("receive");
cc15ab5d 363 if ((so->so_proto->pr_flags & PR_ADDR)) {
2b4b57cd 364 if (asa) {
cc15ab5d 365 so->so_rcv.sb_cc -= m->m_len;
2b4b57cd
BJ
366 len = MIN(m->m_len, sizeof (struct sockaddr));
367 bcopy(mtod(m, caddr_t), (caddr_t)asa, len);
cc15ab5d 368 } else
2b4b57cd 369 bzero((caddr_t)asa, sizeof (*asa));
50fc8df6 370 m = m_free(m);
cc15ab5d
BJ
371 if (m == 0)
372 panic("receive 2");
50fc8df6 373 so->so_rcv.sb_mb = m;
cc15ab5d 374 }
ce9d8eb4
BJ
375 eor = 0;
376 do {
377 len = MIN(m->m_len, u.u_count);
378 if (len == m->m_len) {
379 eor = (int)m->m_act;
cc15ab5d 380 sbfree(&so->so_rcv, m);
ce9d8eb4
BJ
381 }
382 splx(s);
383 iomove(mtod(m, caddr_t), len, B_READ);
384 s = splnet();
385 if (len == m->m_len) {
386 MFREE(m, n);
a4f6d93d 387 so->so_rcv.sb_mb = n;
ce9d8eb4
BJ
388 } else {
389 m->m_off += len;
390 m->m_len -= len;
92a533e6 391 so->so_rcv.sb_cc -= len;
ce9d8eb4 392 }
92a533e6 393 } while ((m = so->so_rcv.sb_mb) && u.u_count && !eor);
ce9d8eb4
BJ
394 if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
395 do {
ce9d8eb4 396 if (m == 0)
cc15ab5d
BJ
397 panic("receive 3");
398 sbfree(&so->so_rcv, m);
ce9d8eb4
BJ
399 eor = (int)m->m_act;
400 so->so_rcv.sb_mb = m->m_next;
401 MFREE(m, n);
cc15ab5d 402 m = n;
ce9d8eb4 403 } while (eor == 0);
cc15ab5d
BJ
404 if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
405 (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
cc15ab5d 406release:
ae921915 407 sbunlock(&so->so_rcv);
cc15ab5d 408 splx(s);
ae921915 409 return (error);
92a533e6
BJ
410}
411
ae921915
BJ
412/*ARGSUSED*/
413soioctl(so, cmd, cmdp)
92a533e6
BJ
414 register struct socket *so;
415 int cmd;
416 register caddr_t cmdp;
417{
418
2b4b57cd 419COUNT(SOIOCTL);
92a533e6
BJ
420 switch (cmdp) {
421
422 }
423 switch (so->so_type) {
424
425 case SOCK_STREAM:
426 break;
427
428 case SOCK_DGRAM:
429 break;
430
431 case SOCK_RDM:
432 break;
433
434 case SOCK_RAW:
435 break;
436
437 }
ce9d8eb4 438}