source: rtems/cpukit/libnetworking/kern/uipc_socket.c @ 4bf1801

4.104.114.84.95
Last change on this file since 4bf1801 was a6f3cff, checked in by Joel Sherrill <joel.sherrill@…>, on 06/11/99 at 14:11:44

Patch from Ian Lance Taylor <ian@…>:

The select function is not particularly efficient when dealing with a
large number of sockets. The application has to build a big set of
bits and pass it in. RTEMS has to look through all those bits and see
what is ready. Then the application has to look through all the bits
again.

On the other hand, when using RTEMS, the select function is needed
exactly when you have a large number of sockets, because that is when
it becomes prohibitive to use a separate thread for each socket.

I think it would make more sense for RTEMS to support callback
functions which could be invoked when there is data available to read
from a socket, or when there is space available to write to a socket.

Accordingly, I implemented them.

This patch adds two new SOL_SOCKET options to setsockopt and
getsockopt: SO_SNDWAKEUP and SO_RCVWAKEUP. They take arguments of
type struct sockwakeup:

struct sockwakeup {

void (*sw_pfn) P((struct socket *, caddr_t));
caddr_t sw_arg;

};

They are used to add or remove a function which will be called when
something happens for the socket. Getting a callback doesn't imply
that a read or write will succeed, but it does imply that it is worth
trying.

This adds functionality to RTEMS which is somewhat like interrupt
driven socket I/O on Unix.

After the patch to RTEMS, I have appended a patch to
netdemos-19990407/select/test.c to test the new functionality and
demonstrate one way it might be used. To run the new test instead of
the select test, change doSocket to call echoServer2 instead of
echoServer.

  • Property mode set to 100644
File size: 26.5 KB
Line 
1/*
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993
3 *      The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *      This product includes software developed by the University of
16 *      California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 *      @(#)uipc_socket.c       8.3 (Berkeley) 4/15/94
34 * $Id$
35 */
36
37#include <sys/param.h>
38#include <sys/queue.h>
39#include <sys/systm.h>
40#include <sys/proc.h>
41#include <sys/file.h>
42#include <sys/malloc.h>
43#include <sys/mbuf.h>
44#include <sys/domain.h>
45#include <sys/kernel.h>
46#include <sys/protosw.h>
47#include <sys/socket.h>
48#include <sys/socketvar.h>
49#include <sys/resourcevar.h>
50#include <sys/signalvar.h>
51#include <sys/sysctl.h>
52#include <limits.h>
53
54static int somaxconn = SOMAXCONN;
55SYSCTL_INT(_kern, KERN_SOMAXCONN, somaxconn, CTLFLAG_RW, &somaxconn, 0, "");
56
57/*
58 * Socket operation routines.
59 * These routines are called by the routines in
60 * sys_socket.c or from a system process, and
61 * implement the semantics of socket operations by
62 * switching out to the protocol specific routines.
63 */
64/*ARGSUSED*/
65int
66socreate(dom, aso, type, proto, p)
67        int dom;
68        struct socket **aso;
69        register int type;
70        int proto;
71        struct proc *p;
72{
73        register struct protosw *prp;
74        register struct socket *so;
75        register int error;
76
77        if (proto)
78                prp = pffindproto(dom, proto, type);
79        else
80                prp = pffindtype(dom, type);
81        if (prp == 0 || prp->pr_usrreqs == 0)
82                return (EPROTONOSUPPORT);
83        if (prp->pr_type != type)
84                return (EPROTOTYPE);
85        MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT);
86        bzero((caddr_t)so, sizeof(*so));
87        TAILQ_INIT(&so->so_incomp);
88        TAILQ_INIT(&so->so_comp);
89        so->so_type = type;
90        so->so_state = SS_PRIV;
91        so->so_uid = 0;
92        so->so_proto = prp;
93        error = (*prp->pr_usrreqs->pru_attach)(so, proto);
94        if (error) {
95                so->so_state |= SS_NOFDREF;
96                sofree(so);
97                return (error);
98        }
99        *aso = so;
100        return (0);
101}
102
103int
104sobind(so, nam)
105        struct socket *so;
106        struct mbuf *nam;
107{
108        int s = splnet();
109        int error;
110
111        error = (*so->so_proto->pr_usrreqs->pru_bind)(so, nam);
112        splx(s);
113        return (error);
114}
115
116int
117solisten(so, backlog)
118        register struct socket *so;
119        int backlog;
120{
121        int s = splnet(), error;
122
123        error = (*so->so_proto->pr_usrreqs->pru_listen)(so);
124        if (error) {
125                splx(s);
126                return (error);
127        }
128        if (so->so_comp.tqh_first == NULL)
129                so->so_options |= SO_ACCEPTCONN;
130        if (backlog < 0 || backlog > somaxconn)
131                backlog = somaxconn;
132        so->so_qlimit = backlog;
133        splx(s);
134        return (0);
135}
136
137void
138sofree(so)
139        register struct socket *so;
140{
141        struct socket *head = so->so_head;
142
143        if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
144                return;
145        if (head != NULL) {
146                if (so->so_state & SS_INCOMP) {
147                        TAILQ_REMOVE(&head->so_incomp, so, so_list);
148                        head->so_incqlen--;
149                } else if (so->so_state & SS_COMP) {
150                        TAILQ_REMOVE(&head->so_comp, so, so_list);
151                } else {
152                        panic("sofree: not queued");
153                }
154                head->so_qlen--;
155                so->so_state &= ~(SS_INCOMP|SS_COMP);
156                so->so_head = NULL;
157        }
158        sbrelease(&so->so_snd);
159        sorflush(so);
160        FREE(so, M_SOCKET);
161}
162
163/*
164 * Close a socket on last file table reference removal.
165 * Initiate disconnect if connected.
166 * Free socket when disconnect complete.
167 */
168int
169soclose(so)
170        register struct socket *so;
171{
172        int s = splnet();               /* conservative */
173        int error = 0;
174
175        if (so->so_options & SO_ACCEPTCONN) {
176                struct socket *sp, *sonext;
177
178                for (sp = so->so_incomp.tqh_first; sp != NULL; sp = sonext) {
179                        sonext = sp->so_list.tqe_next;
180                        (void) soabort(sp);
181                }
182                for (sp = so->so_comp.tqh_first; sp != NULL; sp = sonext) {
183                        sonext = sp->so_list.tqe_next;
184                        (void) soabort(sp);
185                }
186        }
187        if (so->so_pcb == 0)
188                goto discard;
189        if (so->so_state & SS_ISCONNECTED) {
190                if ((so->so_state & SS_ISDISCONNECTING) == 0) {
191                        error = sodisconnect(so);
192                        if (error)
193                                goto drop;
194                }
195                if (so->so_options & SO_LINGER) {
196                        if ((so->so_state & SS_ISDISCONNECTING) &&
197                            (so->so_state & SS_NBIO))
198                                goto drop;
199                        while (so->so_state & SS_ISCONNECTED) {
200                                soconnsleep (so);
201                        }
202                }
203        }
204drop:
205        if (so->so_pcb) {
206                int error2 = (*so->so_proto->pr_usrreqs->pru_detach)(so);
207                if (error == 0)
208                        error = error2;
209        }
210discard:
211        if (so->so_state & SS_NOFDREF)
212                panic("soclose: NOFDREF");
213        so->so_state |= SS_NOFDREF;
214        sofree(so);
215        splx(s);
216        return (error);
217}
218
219/*
220 * Must be called at splnet...
221 */
222int
223soabort(so)
224        struct socket *so;
225{
226
227        return (*so->so_proto->pr_usrreqs->pru_abort)(so);
228}
229
230int
231soaccept(so, nam)
232        register struct socket *so;
233        struct mbuf *nam;
234{
235        int s = splnet();
236        int error;
237
238        if ((so->so_state & SS_NOFDREF) == 0)
239                panic("soaccept: !NOFDREF");
240        so->so_state &= ~SS_NOFDREF;
241        error = (*so->so_proto->pr_usrreqs->pru_accept)(so, nam);
242        splx(s);
243        return (error);
244}
245
246int
247soconnect(so, nam)
248        register struct socket *so;
249        struct mbuf *nam;
250{
251        int s;
252        int error;
253
254        if (so->so_options & SO_ACCEPTCONN)
255                return (EOPNOTSUPP);
256        s = splnet();
257        /*
258         * If protocol is connection-based, can only connect once.
259         * Otherwise, if connected, try to disconnect first.
260         * This allows user to disconnect by connecting to, e.g.,
261         * a null address.
262         */
263        if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
264            ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
265            (error = sodisconnect(so))))
266                error = EISCONN;
267        else
268                error = (*so->so_proto->pr_usrreqs->pru_connect)(so, nam);
269        splx(s);
270        return (error);
271}
272
273int
274soconnect2(so1, so2)
275        register struct socket *so1;
276        struct socket *so2;
277{
278        int s = splnet();
279        int error;
280
281        error = (*so1->so_proto->pr_usrreqs->pru_connect2)(so1, so2);
282        splx(s);
283        return (error);
284}
285
286int
287sodisconnect(so)
288        register struct socket *so;
289{
290        int s = splnet();
291        int error;
292
293        if ((so->so_state & SS_ISCONNECTED) == 0) {
294                error = ENOTCONN;
295                goto bad;
296        }
297        if (so->so_state & SS_ISDISCONNECTING) {
298                error = EALREADY;
299                goto bad;
300        }
301        error = (*so->so_proto->pr_usrreqs->pru_disconnect)(so);
302bad:
303        splx(s);
304        return (error);
305}
306
307#define SBLOCKWAIT(f)   (((f) & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK)
308/*
309 * Send on a socket.
310 * If send must go all at once and message is larger than
311 * send buffering, then hard error.
312 * Lock against other senders.
313 * If must go all at once and not enough room now, then
314 * inform user that this would block and do nothing.
315 * Otherwise, if nonblocking, send as much as possible.
316 * The data to be sent is described by "uio" if nonzero,
317 * otherwise by the mbuf chain "top" (which must be null
318 * if uio is not).  Data provided in mbuf chain must be small
319 * enough to send all at once.
320 *
321 * Returns nonzero on error, timeout or signal; callers
322 * must check for short counts if EINTR/ERESTART are returned.
323 * Data and control buffers are freed on return.
324 */
325int
326sosend(so, addr, uio, top, control, flags)
327        register struct socket *so;
328        struct mbuf *addr;
329        struct uio *uio;
330        struct mbuf *top;
331        struct mbuf *control;
332        int flags;
333{
334        struct mbuf **mp;
335        register struct mbuf *m;
336        register long space, len, resid;
337        int clen = 0, error, s, dontroute, mlen;
338        int atomic = sosendallatonce(so) || top;
339
340        if (uio)
341                resid = uio->uio_resid;
342        else
343                resid = top->m_pkthdr.len;
344        /*
345         * In theory resid should be unsigned.
346         * However, space must be signed, as it might be less than 0
347         * if we over-committed, and we must use a signed comparison
348         * of space and resid.  On the other hand, a negative resid
349         * causes us to loop sending 0-length segments to the protocol.
350         *
351         * Also check to make sure that MSG_EOR isn't used on SOCK_STREAM
352         * type sockets since that's an error.
353         */
354        if ((resid < 0) || (so->so_type == SOCK_STREAM && (flags & MSG_EOR))) {
355                error = EINVAL;
356                goto out;
357        }
358
359        dontroute =
360            (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
361            (so->so_proto->pr_flags & PR_ATOMIC);
362        if (control)
363                clen = control->m_len;
364#define snderr(errno)   { error = errno; splx(s); goto release; }
365
366restart:
367        error = sblock(&so->so_snd, SBLOCKWAIT(flags));
368        if (error)
369                goto out;
370        do {
371                s = splnet();
372                if (so->so_state & SS_CANTSENDMORE)
373                        snderr(EPIPE);
374                if (so->so_error) {
375                        error = so->so_error;
376                        so->so_error = 0;
377                        splx(s);
378                        goto release;
379                }
380                if ((so->so_state & SS_ISCONNECTED) == 0) {
381                        /*
382                         * `sendto' and `sendmsg' is allowed on a connection-
383                         * based socket if it supports implied connect.
384                         * Return ENOTCONN if not connected and no address is
385                         * supplied.
386                         */
387                        if ((so->so_proto->pr_flags & PR_CONNREQUIRED) &&
388                            (so->so_proto->pr_flags & PR_IMPLOPCL) == 0) {
389                                if ((so->so_state & SS_ISCONFIRMING) == 0 &&
390                                    !(resid == 0 && clen != 0))
391                                        snderr(ENOTCONN);
392                        } else if (addr == 0)
393                            snderr(so->so_proto->pr_flags & PR_CONNREQUIRED ?
394                                   ENOTCONN : EDESTADDRREQ);
395                }
396                space = sbspace(&so->so_snd);
397                if (flags & MSG_OOB)
398                        space += 1024;
399                if ((atomic && resid > so->so_snd.sb_hiwat) ||
400                    clen > so->so_snd.sb_hiwat)
401                        snderr(EMSGSIZE);
402                if (space < resid + clen && uio &&
403                    (atomic || space < so->so_snd.sb_lowat || space < clen)) {
404                        if (so->so_state & SS_NBIO)
405                                snderr(EWOULDBLOCK);
406                        sbunlock(&so->so_snd);
407                        error = sbwait(&so->so_snd);
408                        splx(s);
409                        if (error)
410                                goto out;
411                        goto restart;
412                }
413                splx(s);
414                mp = &top;
415                space -= clen;
416                do {
417                    if (uio == NULL) {
418                        /*
419                         * Data is prepackaged in "top".
420                         */
421                        resid = 0;
422                        if (flags & MSG_EOR)
423                                top->m_flags |= M_EOR;
424                    } else do {
425                        if (top == 0) {
426                                MGETHDR(m, M_WAIT, MT_DATA);
427                                mlen = MHLEN;
428                                m->m_pkthdr.len = 0;
429                                m->m_pkthdr.rcvif = (struct ifnet *)0;
430                        } else {
431                                MGET(m, M_WAIT, MT_DATA);
432                                mlen = MLEN;
433                        }
434                        if (resid >= MINCLSIZE) {
435                                MCLGET(m, M_WAIT);
436                                if ((m->m_flags & M_EXT) == 0)
437                                        goto nopages;
438                                mlen = MCLBYTES;
439                                len = min(min(mlen, resid), space);
440                        } else {
441nopages:
442                                len = min(min(mlen, resid), space);
443                                /*
444                                 * For datagram protocols, leave room
445                                 * for protocol headers in first mbuf.
446                                 */
447                                if (atomic && top == 0 && len < mlen)
448                                        MH_ALIGN(m, len);
449                        }
450                        space -= len;
451                        error = uiomove(mtod(m, caddr_t), (int)len, uio);
452                        resid = uio->uio_resid;
453                        m->m_len = len;
454                        *mp = m;
455                        top->m_pkthdr.len += len;
456                        if (error)
457                                goto release;
458                        mp = &m->m_next;
459                        if (resid <= 0) {
460                                if (flags & MSG_EOR)
461                                        top->m_flags |= M_EOR;
462                                break;
463                        }
464                    } while (space > 0 && atomic);
465                    if (dontroute)
466                            so->so_options |= SO_DONTROUTE;
467                    s = splnet();                               /* XXX */
468                    error = (*so->so_proto->pr_usrreqs->pru_send)(so,
469                        (flags & MSG_OOB) ? PRUS_OOB :
470                        /*
471                         * If the user set MSG_EOF, the protocol
472                         * understands this flag and nothing left to
473                         * send then use PRU_SEND_EOF instead of PRU_SEND.
474                         */
475                        ((flags & MSG_EOF) &&
476                         (so->so_proto->pr_flags & PR_IMPLOPCL) &&
477                         (resid <= 0)) ?
478                                PRUS_EOF : 0,
479                        top, addr, control);
480                    splx(s);
481                    if (dontroute)
482                            so->so_options &= ~SO_DONTROUTE;
483                    clen = 0;
484                    control = 0;
485                    top = 0;
486                    mp = &top;
487                    if (error)
488                        goto release;
489                } while (resid && space > 0);
490        } while (resid);
491
492release:
493        sbunlock(&so->so_snd);
494out:
495        if (top)
496                m_freem(top);
497        if (control)
498                m_freem(control);
499        return (error);
500}
501
502/*
503 * Implement receive operations on a socket.
504 * We depend on the way that records are added to the sockbuf
505 * by sbappend*.  In particular, each record (mbufs linked through m_next)
506 * must begin with an address if the protocol so specifies,
507 * followed by an optional mbuf or mbufs containing ancillary data,
508 * and then zero or more mbufs of data.
509 * In order to avoid blocking network interrupts for the entire time here,
510 * we splx() while doing the actual copy to user space.
511 * Although the sockbuf is locked, new data may still be appended,
512 * and thus we must maintain consistency of the sockbuf during that time.
513 *
514 * The caller may receive the data as a single mbuf chain by supplying
515 * an mbuf **mp0 for use in returning the chain.  The uio is then used
516 * only for the count in uio_resid.
517 */
518int
519soreceive(so, paddr, uio, mp0, controlp, flagsp)
520        register struct socket *so;
521        struct mbuf **paddr;
522        struct uio *uio;
523        struct mbuf **mp0;
524        struct mbuf **controlp;
525        int *flagsp;
526{
527        register struct mbuf *m, **mp;
528        register int flags, len, error, s, offset;
529        struct protosw *pr = so->so_proto;
530        struct mbuf *nextrecord;
531        int moff, type = 0;
532        int orig_resid = uio->uio_resid;
533
534        mp = mp0;
535        if (paddr)
536                *paddr = 0;
537        if (controlp)
538                *controlp = 0;
539        if (flagsp)
540                flags = *flagsp &~ MSG_EOR;
541        else
542                flags = 0;
543        if (flags & MSG_OOB) {
544                m = m_get(M_WAIT, MT_DATA);
545                error = (*pr->pr_usrreqs->pru_rcvoob)(so, m, flags & MSG_PEEK);
546                if (error)
547                        goto bad;
548                do {
549                        error = uiomove(mtod(m, caddr_t),
550                            (int) min(uio->uio_resid, m->m_len), uio);
551                        m = m_free(m);
552                } while (uio->uio_resid && error == 0 && m);
553bad:
554                if (m)
555                        m_freem(m);
556                return (error);
557        }
558        if (mp)
559                *mp = (struct mbuf *)0;
560        if (so->so_state & SS_ISCONFIRMING && uio->uio_resid)
561                (*pr->pr_usrreqs->pru_rcvd)(so, 0);
562
563restart:
564        error = sblock(&so->so_rcv, SBLOCKWAIT(flags));
565        if (error)
566                return (error);
567        s = splnet();
568
569        m = so->so_rcv.sb_mb;
570        /*
571         * If we have less data than requested, block awaiting more
572         * (subject to any timeout) if:
573         *   1. the current count is less than the low water mark, or
574         *   2. MSG_WAITALL is set, and it is possible to do the entire
575         *      receive operation at once if we block (resid <= hiwat).
576         *   3. MSG_DONTWAIT is not set
577         * If MSG_WAITALL is set but resid is larger than the receive buffer,
578         * we have to do the receive in sections, and thus risk returning
579         * a short count if a timeout or signal occurs after we start.
580         */
581        if (m == 0 || (((flags & MSG_DONTWAIT) == 0 &&
582            so->so_rcv.sb_cc < uio->uio_resid) &&
583            (so->so_rcv.sb_cc < so->so_rcv.sb_lowat ||
584            ((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) &&
585            m->m_nextpkt == 0 && (pr->pr_flags & PR_ATOMIC) == 0)) {
586#ifdef DIAGNOSTIC
587                if (m == 0 && so->so_rcv.sb_cc)
588                        panic("receive 1");
589#endif
590                if (so->so_error) {
591                        if (m)
592                                goto dontblock;
593                        error = so->so_error;
594                        if ((flags & MSG_PEEK) == 0)
595                                so->so_error = 0;
596                        goto release;
597                }
598                if (so->so_state & SS_CANTRCVMORE) {
599                        if (m)
600                                goto dontblock;
601                        else
602                                goto release;
603                }
604                for (; m; m = m->m_next)
605                        if (m->m_type == MT_OOBDATA  || (m->m_flags & M_EOR)) {
606                                m = so->so_rcv.sb_mb;
607                                goto dontblock;
608                        }
609                if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 &&
610                    (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
611                        error = ENOTCONN;
612                        goto release;
613                }
614                if (uio->uio_resid == 0)
615                        goto release;
616                if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) {
617                        error = EWOULDBLOCK;
618                        goto release;
619                }
620                sbunlock(&so->so_rcv);
621                error = sbwait(&so->so_rcv);
622                splx(s);
623                if (error)
624                        return (error);
625                goto restart;
626        }
627dontblock:
628        nextrecord = m->m_nextpkt;
629        if (pr->pr_flags & PR_ADDR) {
630#ifdef DIAGNOSTIC
631                if (m->m_type != MT_SONAME)
632                        panic("receive 1a");
633#endif
634                orig_resid = 0;
635                if (flags & MSG_PEEK) {
636                        if (paddr)
637                                *paddr = m_copy(m, 0, m->m_len);
638                        m = m->m_next;
639                } else {
640                        sbfree(&so->so_rcv, m);
641                        if (paddr) {
642                                *paddr = m;
643                                so->so_rcv.sb_mb = m->m_next;
644                                m->m_next = 0;
645                                m = so->so_rcv.sb_mb;
646                        } else {
647                                MFREE(m, so->so_rcv.sb_mb);
648                                m = so->so_rcv.sb_mb;
649                        }
650                }
651        }
652        while (m && m->m_type == MT_CONTROL && error == 0) {
653                if (flags & MSG_PEEK) {
654                        if (controlp)
655                                *controlp = m_copy(m, 0, m->m_len);
656                        m = m->m_next;
657                } else {
658                        sbfree(&so->so_rcv, m);
659                        if (controlp) {
660                                if (pr->pr_domain->dom_externalize &&
661                                    mtod(m, struct cmsghdr *)->cmsg_type ==
662                                    SCM_RIGHTS)
663                                   error = (*pr->pr_domain->dom_externalize)(m);
664                                *controlp = m;
665                                so->so_rcv.sb_mb = m->m_next;
666                                m->m_next = 0;
667                                m = so->so_rcv.sb_mb;
668                        } else {
669                                MFREE(m, so->so_rcv.sb_mb);
670                                m = so->so_rcv.sb_mb;
671                        }
672                }
673                if (controlp) {
674                        orig_resid = 0;
675                        controlp = &(*controlp)->m_next;
676                }
677        }
678        if (m) {
679                if ((flags & MSG_PEEK) == 0)
680                        m->m_nextpkt = nextrecord;
681                type = m->m_type;
682                if (type == MT_OOBDATA)
683                        flags |= MSG_OOB;
684        }
685        moff = 0;
686        offset = 0;
687        while (m && uio->uio_resid > 0 && error == 0) {
688                if (m->m_type == MT_OOBDATA) {
689                        if (type != MT_OOBDATA)
690                                break;
691                } else if (type == MT_OOBDATA)
692                        break;
693#ifdef DIAGNOSTIC
694                else if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
695                        panic("receive 3");
696#endif
697                so->so_state &= ~SS_RCVATMARK;
698                len = uio->uio_resid;
699                if (so->so_oobmark && len > so->so_oobmark - offset)
700                        len = so->so_oobmark - offset;
701                if (len > m->m_len - moff)
702                        len = m->m_len - moff;
703                /*
704                 * If mp is set, just pass back the mbufs.
705                 * Otherwise copy them out via the uio, then free.
706                 * Sockbuf must be consistent here (points to current mbuf,
707                 * it points to next record) when we drop priority;
708                 * we must note any additions to the sockbuf when we
709                 * block interrupts again.
710                 */
711                if (mp == 0) {
712                        splx(s);
713                        error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio);
714                        s = splnet();
715                        if (error)
716                                goto release;
717                } else
718                        uio->uio_resid -= len;
719                if (len == m->m_len - moff) {
720                        if (m->m_flags & M_EOR)
721                                flags |= MSG_EOR;
722                        if (flags & MSG_PEEK) {
723                                m = m->m_next;
724                                moff = 0;
725                        } else {
726                                nextrecord = m->m_nextpkt;
727                                sbfree(&so->so_rcv, m);
728                                if (mp) {
729                                        *mp = m;
730                                        mp = &m->m_next;
731                                        so->so_rcv.sb_mb = m = m->m_next;
732                                        *mp = (struct mbuf *)0;
733                                } else {
734                                        MFREE(m, so->so_rcv.sb_mb);
735                                        m = so->so_rcv.sb_mb;
736                                }
737                                if (m)
738                                        m->m_nextpkt = nextrecord;
739                        }
740                } else {
741                        if (flags & MSG_PEEK)
742                                moff += len;
743                        else {
744                                if (mp)
745                                        *mp = m_copym(m, 0, len, M_WAIT);
746                                m->m_data += len;
747                                m->m_len -= len;
748                                so->so_rcv.sb_cc -= len;
749                        }
750                }
751                if (so->so_oobmark) {
752                        if ((flags & MSG_PEEK) == 0) {
753                                so->so_oobmark -= len;
754                                if (so->so_oobmark == 0) {
755                                        so->so_state |= SS_RCVATMARK;
756                                        break;
757                                }
758                        } else {
759                                offset += len;
760                                if (offset == so->so_oobmark)
761                                        break;
762                        }
763                }
764                if (flags & MSG_EOR)
765                        break;
766                /*
767                 * If the MSG_WAITALL flag is set (for non-atomic socket),
768                 * we must not quit until "uio->uio_resid == 0" or an error
769                 * termination.  If a signal/timeout occurs, return
770                 * with a short count but without error.
771                 * Keep sockbuf locked against other readers.
772                 */
773                while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 &&
774                    !sosendallatonce(so) && !nextrecord) {
775                        if (so->so_error || so->so_state & SS_CANTRCVMORE)
776                                break;
777                        error = sbwait(&so->so_rcv);
778                        if (error) {
779                                sbunlock(&so->so_rcv);
780                                splx(s);
781                                return (0);
782                        }
783                        m = so->so_rcv.sb_mb;
784                        if (m)
785                                nextrecord = m->m_nextpkt;
786                }
787        }
788
789        if (m && pr->pr_flags & PR_ATOMIC) {
790                flags |= MSG_TRUNC;
791                if ((flags & MSG_PEEK) == 0)
792                        (void) sbdroprecord(&so->so_rcv);
793        }
794        if ((flags & MSG_PEEK) == 0) {
795                if (m == 0)
796                        so->so_rcv.sb_mb = nextrecord;
797                if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
798                        (*pr->pr_usrreqs->pru_rcvd)(so, flags);
799        }
800        if (orig_resid == uio->uio_resid && orig_resid &&
801            (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) {
802                sbunlock(&so->so_rcv);
803                splx(s);
804                goto restart;
805        }
806
807        if (flagsp)
808                *flagsp |= flags;
809release:
810        sbunlock(&so->so_rcv);
811        splx(s);
812        return (error);
813}
814
815int
816soshutdown(so, how)
817        register struct socket *so;
818        register int how;
819{
820        register struct protosw *pr = so->so_proto;
821
822        how++;
823        if (how & FREAD)
824                sorflush(so);
825        if (how & FWRITE)
826                return ((*pr->pr_usrreqs->pru_shutdown)(so));
827        return (0);
828}
829
830void
831sorflush(so)
832        register struct socket *so;
833{
834        register struct sockbuf *sb = &so->so_rcv;
835        register struct protosw *pr = so->so_proto;
836        register int s;
837        struct sockbuf asb;
838
839        sb->sb_flags |= SB_NOINTR;
840        (void) sblock(sb, M_WAITOK);
841        s = splimp();
842        socantrcvmore(so);
843        sbunlock(sb);
844        asb = *sb;
845        bzero((caddr_t)sb, sizeof (*sb));
846        splx(s);
847        if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
848                (*pr->pr_domain->dom_dispose)(asb.sb_mb);
849        sbrelease(&asb);
850}
851
852int
853sosetopt(so, level, optname, m0)
854        register struct socket *so;
855        int level, optname;
856        struct mbuf *m0;
857{
858        int error = 0;
859        register struct mbuf *m = m0;
860
861        if (level != SOL_SOCKET) {
862                if (so->so_proto && so->so_proto->pr_ctloutput)
863                        return ((*so->so_proto->pr_ctloutput)
864                                  (PRCO_SETOPT, so, level, optname, &m0));
865                error = ENOPROTOOPT;
866        } else {
867                switch (optname) {
868
869                case SO_LINGER:
870                        if (m == NULL || m->m_len != sizeof (struct linger)) {
871                                error = EINVAL;
872                                goto bad;
873                        }
874                        so->so_linger = mtod(m, struct linger *)->l_linger;
875                        /* fall thru... */
876
877                case SO_DEBUG:
878                case SO_KEEPALIVE:
879                case SO_DONTROUTE:
880                case SO_USELOOPBACK:
881                case SO_BROADCAST:
882                case SO_REUSEADDR:
883                case SO_REUSEPORT:
884                case SO_OOBINLINE:
885                case SO_TIMESTAMP:
886                        if (m == NULL || m->m_len < sizeof (int)) {
887                                error = EINVAL;
888                                goto bad;
889                        }
890                        if (*mtod(m, int *))
891                                so->so_options |= optname;
892                        else
893                                so->so_options &= ~optname;
894                        break;
895
896                case SO_SNDBUF:
897                case SO_RCVBUF:
898                case SO_SNDLOWAT:
899                case SO_RCVLOWAT:
900                    {
901                        int optval;
902
903                        if (m == NULL || m->m_len < sizeof (int)) {
904                                error = EINVAL;
905                                goto bad;
906                        }
907
908                        /*
909                         * Values < 1 make no sense for any of these
910                         * options, so disallow them.
911                         */
912                        optval = *mtod(m, int *);
913                        if (optval < 1) {
914                                error = EINVAL;
915                                goto bad;
916                        }
917
918                        switch (optname) {
919
920                        case SO_SNDBUF:
921                        case SO_RCVBUF:
922                                if (sbreserve(optname == SO_SNDBUF ?
923                                    &so->so_snd : &so->so_rcv,
924                                    (u_long) optval) == 0) {
925                                        error = ENOBUFS;
926                                        goto bad;
927                                }
928                                break;
929
930                        /*
931                         * Make sure the low-water is never greater than
932                         * the high-water.
933                         */
934                        case SO_SNDLOWAT:
935                                so->so_snd.sb_lowat =
936                                    (optval > so->so_snd.sb_hiwat) ?
937                                    so->so_snd.sb_hiwat : optval;
938                                break;
939                        case SO_RCVLOWAT:
940                                so->so_rcv.sb_lowat =
941                                    (optval > so->so_rcv.sb_hiwat) ?
942                                    so->so_rcv.sb_hiwat : optval;
943                                break;
944                        }
945                        break;
946                    }
947
948                case SO_SNDTIMEO:
949                case SO_RCVTIMEO:
950                    {
951                        struct timeval *tv;
952                        unsigned long val;
953
954                        if (m == NULL || m->m_len < sizeof (*tv)) {
955                                error = EINVAL;
956                                goto bad;
957                        }
958                        tv = mtod(m, struct timeval *);
959                        if (tv->tv_sec >= (ULONG_MAX - hz) / hz) {
960                                error = EDOM;
961                                goto bad;
962                        }
963                        val = tv->tv_sec * hz + tv->tv_usec / tick;
964
965                        switch (optname) {
966
967                        case SO_SNDTIMEO:
968                                so->so_snd.sb_timeo = val;
969                                break;
970                        case SO_RCVTIMEO:
971                                so->so_rcv.sb_timeo = val;
972                                break;
973                        }
974                        break;
975                    }
976
977                case SO_PRIVSTATE:
978                        /* we don't care what the parameter is... */
979                        so->so_state &= ~SS_PRIV;
980                        break;
981
982                case SO_SNDWAKEUP:
983                case SO_RCVWAKEUP:
984                    {
985                        /* RTEMS addition.  */
986                        struct sockwakeup *sw;
987                        struct sockbuf *sb;
988
989                        if (m == NULL
990                            || m->m_len != sizeof (struct sockwakeup)) {
991                                error = EINVAL;
992                                goto bad;
993                        }
994                        sw = mtod(m, struct sockwakeup *);
995                        sb = (optname == SO_SNDWAKEUP
996                              ? &so->so_snd
997                              : &so->so_rcv);
998                        sb->sb_wakeup = sw->sw_pfn;
999                        sb->sb_wakeuparg = sw->sw_arg;
1000                        if (sw->sw_pfn)
1001                                sb->sb_flags |= SB_ASYNC;
1002                        else
1003                                sb->sb_flags &=~ SB_ASYNC;
1004                        break;
1005                    }
1006
1007                default:
1008                        error = ENOPROTOOPT;
1009                        break;
1010                }
1011                if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) {
1012                        (void) ((*so->so_proto->pr_ctloutput)
1013                                  (PRCO_SETOPT, so, level, optname, &m0));
1014                        m = NULL;       /* freed by protocol */
1015                }
1016        }
1017bad:
1018        if (m)
1019                (void) m_free(m);
1020        return (error);
1021}
1022
1023int
1024sogetopt(so, level, optname, mp)
1025        register struct socket *so;
1026        int level, optname;
1027        struct mbuf **mp;
1028{
1029        register struct mbuf *m;
1030
1031        if (level != SOL_SOCKET) {
1032                if (so->so_proto && so->so_proto->pr_ctloutput) {
1033                        return ((*so->so_proto->pr_ctloutput)
1034                                  (PRCO_GETOPT, so, level, optname, mp));
1035                } else
1036                        return (ENOPROTOOPT);
1037        } else {
1038                m = m_get(M_WAIT, MT_SOOPTS);
1039                m->m_len = sizeof (int);
1040
1041                switch (optname) {
1042
1043                case SO_LINGER:
1044                        m->m_len = sizeof (struct linger);
1045                        mtod(m, struct linger *)->l_onoff =
1046                                so->so_options & SO_LINGER;
1047                        mtod(m, struct linger *)->l_linger = so->so_linger;
1048                        break;
1049
1050                case SO_USELOOPBACK:
1051                case SO_DONTROUTE:
1052                case SO_DEBUG:
1053                case SO_KEEPALIVE:
1054                case SO_REUSEADDR:
1055                case SO_REUSEPORT:
1056                case SO_BROADCAST:
1057                case SO_OOBINLINE:
1058                case SO_TIMESTAMP:
1059                        *mtod(m, int *) = so->so_options & optname;
1060                        break;
1061
1062                case SO_PRIVSTATE:
1063                        *mtod(m, int *) = so->so_state & SS_PRIV;
1064                        break;
1065
1066                case SO_TYPE:
1067                        *mtod(m, int *) = so->so_type;
1068                        break;
1069
1070                case SO_ERROR:
1071                        *mtod(m, int *) = so->so_error;
1072                        so->so_error = 0;
1073                        break;
1074
1075                case SO_SNDBUF:
1076                        *mtod(m, int *) = so->so_snd.sb_hiwat;
1077                        break;
1078
1079                case SO_RCVBUF:
1080                        *mtod(m, int *) = so->so_rcv.sb_hiwat;
1081                        break;
1082
1083                case SO_SNDLOWAT:
1084                        *mtod(m, int *) = so->so_snd.sb_lowat;
1085                        break;
1086
1087                case SO_RCVLOWAT:
1088                        *mtod(m, int *) = so->so_rcv.sb_lowat;
1089                        break;
1090
1091                case SO_SNDTIMEO:
1092                case SO_RCVTIMEO:
1093                    {
1094                        unsigned long val = (optname == SO_SNDTIMEO ?
1095                             so->so_snd.sb_timeo : so->so_rcv.sb_timeo);
1096
1097                        m->m_len = sizeof(struct timeval);
1098                        mtod(m, struct timeval *)->tv_sec = val / hz;
1099                        mtod(m, struct timeval *)->tv_usec =
1100                            (val % hz) * tick;
1101                        break;
1102                    }
1103
1104                case SO_SNDWAKEUP:
1105                case SO_RCVWAKEUP:
1106                    {
1107                        struct sockbuf *sb;
1108                        struct sockwakeup *sw;
1109
1110                        /* RTEMS additions.  */
1111                        sb = (optname == SO_SNDWAKEUP
1112                              ? &so->so_snd
1113                              : &so->so_rcv);
1114                        m->m_len = sizeof (struct sockwakeup);
1115                        sw = mtod(m, struct sockwakeup *);
1116                        sw->sw_pfn = sb->sb_wakeup;
1117                        sw->sw_arg = sb->sb_wakeuparg;
1118                        break;
1119                    }
1120
1121                default:
1122                        (void)m_free(m);
1123                        return (ENOPROTOOPT);
1124                }
1125                *mp = m;
1126                return (0);
1127        }
1128}
1129
1130void
1131sohasoutofband(so)
1132        register struct socket *so;
1133{
1134#if 0   /* FIXME: For now we just ignore out of band data */
1135        struct proc *p;
1136
1137        if (so->so_pgid < 0)
1138                gsignal(-so->so_pgid, SIGURG);
1139        else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0)
1140                psignal(p, SIGURG);
1141        selwakeup(&so->so_rcv.sb_sel);
1142#endif
1143}
Note: See TracBrowser for help on using the repository browser.