insert SBCHECK calls looking for panic:receive problem
[unix-history] / usr / src / sys / kern / uipc_socket.c
... / ...
CommitLineData
1/* uipc_socket.c 4.53 82/10/16 */
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 "../h/ioctl.h"
17#include "../h/uio.h"
18#include "../net/route.h"
19
20/*
21 * Socket operation routines.
22 * These routines are called by the routines in
23 * sys_socket.c or from a system process, and
24 * implement the semantics of socket operations by
25 * switching out to the protocol specific routines.
26 */
27
28socreate(dom, aso, type, proto, opt)
29 struct socket **aso;
30 int type, proto;
31 struct socketopt *opt;
32{
33 register struct protosw *prp;
34 register struct socket *so;
35 struct mbuf *m;
36 int pf, error;
37
38 pf = dom ? PF_UNIX : PF_INET; /* should be u.u_protof */
39 if (proto)
40 prp = pffindproto(pf, proto);
41 else
42 prp = pffindtype(pf, type);
43 if (prp == 0)
44 return (EPROTONOSUPPORT);
45 if (prp->pr_type != type)
46 return (EPROTOTYPE);
47 m = m_getclr(M_WAIT);
48 if (m == 0)
49 return (ENOBUFS);
50 so = mtod(m, struct socket *);
51 so->so_options = 0;
52 so->so_state = 0;
53 if (u.u_uid == 0)
54 so->so_state = SS_PRIV;
55 so->so_proto = prp;
56 error = (*prp->pr_usrreq)(so, PRU_ATTACH,
57 (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
58 if (error) {
59 so->so_state |= SS_NOFDREF;
60 sofree(so);
61 return (error);
62 }
63 *aso = so;
64 return (0);
65}
66
67sobind(so, nam, opt)
68 struct socket *so;
69 struct mbuf *nam;
70 struct socketopt *opt;
71{
72 int s = splnet();
73 int error;
74
75 error =
76 (*so->so_proto->pr_usrreq)(so, PRU_BIND,
77 (struct mbuf *)0, nam, opt);
78 splx(s);
79 return (error);
80}
81
82solisten(so, backlog)
83 struct socket *so;
84 int backlog;
85{
86 int s = splnet();
87 int error;
88
89 error = (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
90 (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
91 if (error) {
92 splx(s);
93 return (error);
94 }
95 if (so->so_q == 0) {
96 so->so_q = so;
97 so->so_q0 = so;
98 so->so_options |= SO_ACCEPTCONN;
99 }
100 if (backlog < 0)
101 backlog = 0;
102 so->so_qlimit = backlog < 5 ? backlog : 5;
103 so->so_options |= SO_NEWFDONCONN;
104 return (0);
105}
106
107sofree(so)
108 struct socket *so;
109{
110
111 if (so->so_head) {
112 if (!soqremque(so, 0) && !soqremque(so, 1))
113 panic("sofree dq");
114 so->so_head = 0;
115 }
116 if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
117 return;
118 sbrelease(&so->so_snd);
119 sbrelease(&so->so_rcv);
120 (void) m_free(dtom(so));
121}
122
123/*
124 * Close a socket on last file table reference removal.
125 * Initiate disconnect if connected.
126 * Free socket when disconnect complete.
127 */
128soclose(so, exiting)
129 register struct socket *so;
130 int exiting;
131{
132 int s = splnet(); /* conservative */
133
134 if (so->so_options & SO_ACCEPTCONN) {
135 while (so->so_q0 != so)
136 soclose(so->so_q0, 1);
137 while (so->so_q != so)
138 soclose(so->so_q, 1);
139 }
140 if (so->so_pcb == 0)
141 goto discard;
142 if (exiting)
143 so->so_options |= SO_KEEPALIVE;
144 if (so->so_state & SS_ISCONNECTED) {
145 if ((so->so_state & SS_ISDISCONNECTING) == 0) {
146 u.u_error = sodisconnect(so, (struct sockaddr *)0);
147 if (u.u_error) {
148 if (exiting)
149 goto drop;
150 splx(s);
151 return;
152 }
153 }
154 if ((so->so_options & SO_DONTLINGER) == 0) {
155 if ((so->so_state & SS_ISDISCONNECTING) &&
156 (so->so_state & SS_NBIO) &&
157 exiting == 0) {
158 u.u_error = EINPROGRESS;
159 splx(s);
160 return;
161 }
162 /* should use tsleep here, for at most linger */
163 while (so->so_state & SS_ISCONNECTED)
164 sleep((caddr_t)&so->so_timeo, PZERO+1);
165 }
166 }
167drop:
168 if (so->so_pcb) {
169 u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
170 (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
171 if (exiting == 0 && u.u_error) {
172 splx(s);
173 return;
174 }
175 }
176discard:
177 so->so_state |= SS_NOFDREF;
178 sofree(so);
179 splx(s);
180}
181
182/*ARGSUSED*/
183sostat(so, sb)
184 struct socket *so;
185 struct stat *sb;
186{
187
188 bzero((caddr_t)sb, sizeof (*sb)); /* XXX */
189 return (0); /* XXX */
190}
191
192soaccept(so, nam, opt)
193 struct socket *so;
194 struct mbuf *nam;
195 struct socketopt *opt;
196{
197 int s = splnet();
198 int error;
199
200 error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
201 (struct mbuf *)0, nam, opt);
202 splx(s);
203 return (error);
204}
205
206soconnect(so, nam, opt)
207 struct socket *so;
208 struct mbuf *nam;
209 struct socketopt *opt;
210{
211 int s = splnet();
212 int error;
213
214 if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
215 error = EISCONN;
216 goto bad;
217 }
218 error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
219 (struct mbuf *)0, nam, opt);
220bad:
221 splx(s);
222 return (error);
223}
224
225sodisconnect(so, nam)
226 struct socket *so;
227 struct mbuf *nam;
228{
229 int s = splnet();
230 int error;
231
232 if ((so->so_state & SS_ISCONNECTED) == 0) {
233 error = ENOTCONN;
234 goto bad;
235 }
236 if (so->so_state & SS_ISDISCONNECTING) {
237 error = EALREADY;
238 goto bad;
239 }
240 error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
241 (struct mbuf *)0, nam, (struct socketopt *)0);
242bad:
243 splx(s);
244 return (error);
245}
246
247/*
248 * Send on a socket.
249 * If send must go all at once and message is larger than
250 * send buffering, then hard error.
251 * Lock against other senders.
252 * If must go all at once and not enough room now, then
253 * inform user that this would block and do nothing.
254 */
255sosend(so, nam, uio, flags)
256 register struct socket *so;
257 struct mbuf *nam;
258 struct uio *uio;
259 int flags;
260{
261 struct mbuf *top = 0;
262 register struct mbuf *m, **mp = &top;
263 register u_int len;
264 int error = 0, space, s;
265
266 if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat)
267 return (EMSGSIZE);
268restart:
269 sblock(&so->so_snd);
270#define snderr(errno) { error = errno; splx(s); goto release; }
271
272 u.u_ru.ru_msgsnd++;
273again:
274 s = splnet();
275 if (so->so_state & SS_CANTSENDMORE) {
276 psignal(u.u_procp, SIGPIPE);
277 snderr(EPIPE);
278 }
279 if (so->so_error) {
280 error = so->so_error;
281 so->so_error = 0; /* ??? */
282 splx(s);
283 goto release;
284 }
285 if ((so->so_state & SS_ISCONNECTED) == 0) {
286 if (so->so_proto->pr_flags & PR_CONNREQUIRED)
287 snderr(ENOTCONN);
288 if (nam == 0)
289 snderr(EDESTADDRREQ);
290 }
291 if (top) {
292 error = (*so->so_proto->pr_usrreq)(so,
293 (flags & SOF_OOB) ? PRU_SENDOOB : PRU_SEND,
294 top, (caddr_t)nam, (struct socketopt *)0);
295 top = 0;
296 if (error) {
297 splx(s);
298 goto release;
299 }
300 mp = &top;
301 }
302 if (uio->uio_resid == 0) {
303 splx(s);
304 goto release;
305 }
306 if (flags & SOF_OOB)
307 space = 1024;
308 else {
309 space = sbspace(&so->so_snd);
310 if (space <= 0 ||
311 sosendallatonce(so) && space < uio->uio_resid) {
312 if (so->so_state & SS_NBIO)
313 snderr(EWOULDBLOCK);
314 sbunlock(&so->so_snd);
315 sbwait(&so->so_snd);
316 splx(s);
317 goto restart;
318 }
319 }
320 splx(s);
321 while (uio->uio_resid > 0 && space > 0) {
322 register struct iovec *iov = uio->uio_iov;
323
324 if (iov->iov_len == 0) {
325 uio->uio_iov++;
326 uio->uio_iovcnt--;
327 if (uio->uio_iovcnt < 0)
328 panic("sosend");
329 continue;
330 }
331 MGET(m, 1);
332 if (m == NULL) {
333 error = ENOBUFS; /* SIGPIPE? */
334 goto release;
335 }
336 if (iov->iov_len >= CLBYTES && space >= CLBYTES) {
337 register struct mbuf *p;
338 MCLGET(p, 1);
339 if (p == 0)
340 goto nopages;
341 m->m_off = (int)p - (int)m;
342 len = CLBYTES;
343 } else {
344nopages:
345 len = MIN(MLEN, iov->iov_len);
346 }
347 uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
348 m->m_len = len;
349 *mp = m;
350 mp = &m->m_next;
351 if (flags & SOF_OOB)
352 space -= len;
353 else
354 space = sbspace(&so->so_snd);
355 }
356 goto again;
357
358release:
359 sbunlock(&so->so_snd);
360 if (top)
361 m_freem(top);
362 return (error);
363}
364
365soreceive(so, aname, uio, flags)
366 register struct socket *so;
367 struct mbuf **aname;
368 struct uio *uio;
369 int flags;
370{
371 register struct iovec *iov;
372 register struct mbuf *m, *n;
373 u_int len;
374 int eor, s, error = 0, moff, tomark;
375
376 if (flags & SOF_OOB) {
377 struct mbuf *m = m_get(M_WAIT);
378
379 (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB,
380 m, (struct mbuf *)0, (struct socketopt *)0);
381 len = uio->uio_resid;
382 do {
383 if (len > m->m_len)
384 len = m->m_len;
385 uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
386 m = m_free(m);
387 } while (uio->uio_resid && u.u_error == 0 && m);
388 if (m)
389 (void) m_freem(m);
390 return;
391 }
392
393restart:
394 sblock(&so->so_rcv);
395SBCHECK(&so->so_snd, "soreceive restart");
396 s = splnet();
397
398#define rcverr(errno) { error = errno; splx(s); goto release; }
399 if (so->so_rcv.sb_cc == 0) {
400 if (so->so_error) {
401 error = so->so_error;
402 so->so_error = 0;
403 splx(s);
404 goto release;
405 }
406 if (so->so_state & SS_CANTRCVMORE) {
407 splx(s);
408 goto release;
409 }
410 if ((so->so_state & SS_ISCONNECTED) == 0 &&
411 (so->so_proto->pr_flags & PR_CONNREQUIRED))
412 rcverr(ENOTCONN);
413 if (so->so_state & SS_NBIO)
414 rcverr(EWOULDBLOCK);
415 sbunlock(&so->so_rcv);
416 sbwait(&so->so_rcv);
417 splx(s);
418 goto restart;
419 }
420 u.u_ru.ru_msgrcv++;
421 m = so->so_rcv.sb_mb;
422 if (m == 0)
423 panic("receive");
424SBCHECK(&so->so_snd, "soreceive havecc");
425 if (so->so_proto->pr_flags & PR_ADDR) {
426 if ((flags & SOF_PREVIEW) == 0) {
427 so->so_rcv.sb_cc -= m->m_len;
428 so->so_rcv.sb_mbcnt -= MSIZE;
429 }
430 if (aname) {
431 if (flags & SOF_PREVIEW)
432 *aname = m_copy(m, 0, m->m_len);
433 else
434 *aname = m;
435 m = m->m_next;
436 (*aname)->m_next = 0;
437 } else
438 if (flags & SOF_PREVIEW)
439 m = m->m_next;
440 else
441 m = m_free(m);
442 if (m == 0)
443 panic("receive 2");
444 if ((flags & SOF_PREVIEW) == 0)
445 so->so_rcv.sb_mb = m;
446SBCHECK(&so->so_snd, "soreceive afteraddr");
447 }
448 eor = 0;
449 moff = 0;
450 tomark = so->so_oobmark;
451 do {
452 if (uio->uio_resid <= 0)
453 break;
454 len = uio->uio_resid;
455 so->so_state &= ~SS_RCVATMARK;
456 if (tomark && len > tomark)
457 len = tomark;
458 if (moff+len > m->m_len - moff)
459 len = m->m_len - moff;
460 splx(s);
461 uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio);
462 s = splnet();
463 if (len == m->m_len) {
464 eor = (int)m->m_act;
465 if (flags & SOF_PREVIEW)
466 m = m->m_next;
467 else {
468 sbfree(&so->so_rcv, m);
469 MFREE(m, n);
470 m = n;
471 so->so_rcv.sb_mb = m;
472 }
473 moff = 0;
474 } else {
475 if (flags & SOF_PREVIEW)
476 moff += len;
477 else {
478 m->m_off += len;
479 m->m_len -= len;
480 so->so_rcv.sb_cc -= len;
481 }
482 }
483 if ((flags & SOF_PREVIEW) == 0 && so->so_oobmark) {
484 so->so_oobmark -= len;
485 if (so->so_oobmark == 0) {
486 so->so_state |= SS_RCVATMARK;
487 break;
488 }
489 }
490 if (tomark) {
491 tomark -= len;
492 if (tomark == 0)
493 break;
494 }
495SBCHECK(&so->so_snd, "soreceive rcvloop");
496 } while (m && !eor);
497 if (flags & SOF_PREVIEW)
498 goto release;
499 if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
500 do {
501 if (m == 0)
502 panic("receive 3");
503 sbfree(&so->so_rcv, m);
504 eor = (int)m->m_act;
505 so->so_rcv.sb_mb = m->m_next;
506 MFREE(m, n);
507 m = n;
508SBCHECK(&so->so_snd, "soreceive atomicloop");
509 } while (eor == 0);
510 if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
511 (*so->so_proto->pr_usrreq)(so, PRU_RCVD,
512 (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
513release:
514 sbunlock(&so->so_rcv);
515 splx(s);
516 return (error);
517}
518
519sohasoutofband(so)
520 struct socket *so;
521{
522
523 if (so->so_pgrp == 0)
524 return;
525 if (so->so_pgrp > 0)
526 gsignal(so->so_pgrp, SIGURG);
527 else {
528 struct proc *p = pfind(-so->so_pgrp);
529
530 if (p)
531 psignal(p, SIGURG);
532 }
533}
534
535/*ARGSUSED*/
536soioctl(so, cmd, data)
537 register struct socket *so;
538 int cmd;
539 register char *data;
540{
541
542 switch (cmd) {
543
544 case FIONBIO:
545 if (*(int *)data)
546 so->so_state |= SS_NBIO;
547 else
548 so->so_state &= ~SS_NBIO;
549 return;
550
551 case FIOASYNC:
552 if (*(int *)data)
553 so->so_state |= SS_ASYNC;
554 else
555 so->so_state &= ~SS_ASYNC;
556 return;
557
558 case SIOCSKEEP:
559 if (*(int *)data)
560 so->so_options &= ~SO_KEEPALIVE;
561 else
562 so->so_options |= SO_KEEPALIVE;
563 return;
564
565 case SIOCGKEEP:
566 *(int *)data = (so->so_options & SO_KEEPALIVE) != 0;
567 return;
568
569 case SIOCSLINGER:
570 so->so_linger = *(int *)data;
571 if (so->so_linger)
572 so->so_options &= ~SO_DONTLINGER;
573 else
574 so->so_options |= SO_DONTLINGER;
575 return;
576
577 case SIOCGLINGER:
578 *(int *)data = so->so_linger;
579 return;
580
581 case SIOCSPGRP:
582 so->so_pgrp = *(int *)data;
583 return;
584
585 case SIOCGPGRP:
586 *(int *)data = so->so_pgrp;
587 return;
588
589 case SIOCDONE: {
590 int flags = *(int *)data;
591
592 flags++;
593 if (flags & FREAD) {
594 int s = splimp();
595 socantrcvmore(so);
596 sbflush(&so->so_rcv);
597 splx(s);
598 }
599 if (flags & FWRITE)
600 u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN,
601 (struct mbuf *)0, (struct mbuf *)0,
602 (struct socketopt *)0);
603 return;
604 }
605
606 case SIOCSENDOOB: {
607 char oob = *(char *)data;
608 struct mbuf *m = m_get(M_DONTWAIT);
609
610 if (m == 0) {
611 u.u_error = ENOBUFS;
612 return;
613 }
614 m->m_len = 1;
615 *mtod(m, char *) = oob;
616 (*so->so_proto->pr_usrreq)(so, PRU_SENDOOB,
617 m, (struct mbuf *)0, (struct socketopt *)0);
618 return;
619 }
620
621 case SIOCRCVOOB: {
622 struct mbuf *m = m_get(M_WAIT);
623
624 if (m == 0) {
625 u.u_error = ENOBUFS;
626 return;
627 }
628 *mtod(m, caddr_t) = 0;
629 (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB,
630 m, (struct mbuf *)0, (struct socketopt *)0);
631 *(char *)data = *mtod(m, char *);
632 (void) m_free(m);
633 return;
634 }
635
636 case SIOCATMARK:
637 *(int *)data = (so->so_state&SS_RCVATMARK) != 0;
638 return;
639
640 /* routing table update calls */
641 case SIOCADDRT:
642 case SIOCDELRT:
643 if (!suser())
644 return;
645 u.u_error = rtrequest(cmd, (struct rtentry *)data);
646 return;
647
648 /* type/protocol specific ioctls */
649 }
650 u.u_error = EOPNOTSUPP;
651}