source: rtems/c/src/lib/libnetworking/rtems/rtems_syscall.c @ af020036

4.104.114.84.95
Last change on this file since af020036 was af020036, checked in by Joel Sherrill <joel.sherrill@…>, on 03/19/99 at 21:51:58

Patch from Eric Norum <eric@…> that adds external
fcntl support and an external fcntl handler for sockets.

  • Property mode set to 100644
File size: 15.2 KB
Line 
1/*
2 *  $Id$
3 */
4
5#include <string.h>
6#include <stdarg.h>
7#include <stdlib.h>
8#include <stdio.h>
9
10#include <rtems.h>
11#include <rtems/libio.h>
12#include <rtems/error.h>
13#include <rtems/rtems_bsdnet.h>
14
15#include <sys/errno.h>
16#include <sys/types.h>
17#include <sys/param.h>
18#include <sys/mbuf.h>
19#include <sys/socket.h>
20#include <sys/socketvar.h>
21#include <sys/protosw.h>
22#include <sys/proc.h>
23#include <sys/fcntl.h>
24#include <sys/filio.h>
25
26#include <net/if.h>
27#include <net/route.h>
28
29/*
30 * Hooks to RTEMS I/O system
31 */
32static const rtems_filesystem_file_handlers_r socket_handlers;
33int rtems_bsdnet_makeFdForSocket(void *so, const rtems_filesystem_file_handlers_r *h);
34struct socket *rtems_bsdnet_fdToSocket(int fd);
35
36/*
37 * Package system call argument into mbuf.
38 */
39static int
40sockargstombuf (struct mbuf **mp, const void *buf, int buflen, int type)
41{
42        struct mbuf *m;
43
44        if ((u_int)buflen > MLEN)
45                return (EINVAL);
46        m = m_get(M_WAIT, type);
47        if (m == NULL)
48                return (ENOBUFS);
49        m->m_len = buflen;
50        memcpy (mtod(m, caddr_t), buf, buflen);
51        *mp = m;
52        if (type == MT_SONAME) {
53                struct sockaddr *sa;
54                sa = mtod(m, struct sockaddr *);
55                sa->sa_len = buflen;
56        }
57        return 0;
58}
59
60/*
61 *********************************************************************
62 *                       BSD-style entry points                      *
63 *********************************************************************
64 */
65int
66socket (int domain, int type, int protocol)
67{
68        int fd;
69        int error;
70        struct socket *so;
71
72        rtems_bsdnet_semaphore_obtain ();
73        error = socreate(domain, &so, type, protocol, NULL);
74        if (error == 0) {
75                fd = rtems_bsdnet_makeFdForSocket (so, &socket_handlers);
76                if (fd < 0)
77                        soclose (so);
78        }
79        else {
80                errno = error;
81                fd = -1;
82        }
83        rtems_bsdnet_semaphore_release ();
84        return fd;
85}
86
87int
88bind (int s, struct sockaddr *name, int namelen)
89{
90        int error;
91        int ret = -1;
92        struct socket *so;
93        struct mbuf *nam;
94
95        rtems_bsdnet_semaphore_obtain ();
96        if ((so = rtems_bsdnet_fdToSocket (s)) != NULL) {
97                error = sockargstombuf (&nam, name, namelen, MT_SONAME);
98                if (error == 0) {
99                        error = sobind (so, nam);
100                        if (error == 0)
101                                ret = 0;
102                        else
103                                errno = error;
104                        m_freem (nam);
105                }
106                else {
107                        errno = error;
108                }
109        }
110        rtems_bsdnet_semaphore_release ();
111        return ret;
112}
113
114int
115connect (int s, struct sockaddr *name, int namelen)
116{
117        int error;
118        int ret = -1;
119        struct socket *so;
120        struct mbuf *nam;
121
122        rtems_bsdnet_semaphore_obtain ();
123        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
124                rtems_bsdnet_semaphore_release ();
125                return -1;
126        }
127        if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
128                errno = EALREADY;
129                rtems_bsdnet_semaphore_release ();
130                return -1;
131        }
132        error = sockargstombuf (&nam, name, namelen, MT_SONAME);
133        if (error) {
134                errno = error;
135                rtems_bsdnet_semaphore_release ();
136                return -1;
137        }
138        error = soconnect (so, nam);
139        if (error) {
140                errno = error;
141                rtems_bsdnet_semaphore_release ();
142                return -1;
143        }
144        if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
145                m_freem(nam);
146                errno = EINPROGRESS;
147                rtems_bsdnet_semaphore_release ();
148                return -1;
149        }
150        while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
151                so->so_error = soconnsleep (so);
152        }
153        if (error == 0) {
154                error = so->so_error;
155                so->so_error = 0;
156        }
157        so->so_state &= ~SS_ISCONNECTING;
158        m_freem (nam);
159        if (error == 0)
160                ret = 0;
161        rtems_bsdnet_semaphore_release ();
162        return ret;
163}
164
165int
166listen (int s, int backlog)
167{
168        int error;
169        int ret = -1;
170        struct socket *so;
171
172        rtems_bsdnet_semaphore_obtain ();
173        if ((so = rtems_bsdnet_fdToSocket (s)) != NULL) {
174                error = solisten (so, backlog);
175                if (error == 0)
176                        ret = 0;
177                else
178                        errno = error;
179        }
180        rtems_bsdnet_semaphore_release ();
181        return ret;
182}
183
184int
185accept (int s, struct sockaddr *name, int *namelen)
186{
187        int fd;
188        struct socket *head, *so;
189        struct mbuf *nam;
190
191        rtems_bsdnet_semaphore_obtain ();
192        if ((head = rtems_bsdnet_fdToSocket (s)) == NULL) {
193                rtems_bsdnet_semaphore_release ();
194                return -1;
195        }
196        if ((head->so_options & SO_ACCEPTCONN) == 0) {
197                errno = EINVAL;
198                rtems_bsdnet_semaphore_release ();
199                return -1;
200        }
201        if ((head->so_state & SS_NBIO) && head->so_comp.tqh_first == NULL) {
202                errno = EWOULDBLOCK;
203                rtems_bsdnet_semaphore_release ();
204                return -1;
205        }
206        while (head->so_comp.tqh_first == NULL && head->so_error == 0) {
207                if (head->so_state & SS_CANTRCVMORE) {
208                        head->so_error = ECONNABORTED;
209                        break;
210                }
211                head->so_error = soconnsleep (head);
212        }
213        if (head->so_error) {
214                errno = head->so_error;
215                head->so_error = 0;
216                rtems_bsdnet_semaphore_release ();
217                return -1;
218        }
219
220        so = head->so_comp.tqh_first;
221        TAILQ_REMOVE(&head->so_comp, so, so_list);
222        head->so_qlen--;
223
224        fd = rtems_bsdnet_makeFdForSocket (so, &socket_handlers);
225        if (fd < 0) {
226                TAILQ_INSERT_HEAD(&head->so_comp, so, so_list);
227                head->so_qlen++;
228                soconnwakeup (head);
229                rtems_bsdnet_semaphore_release ();
230                return -1;
231        }
232        so->so_state &= ~SS_COMP;
233        so->so_head = NULL;
234
235        nam = m_get(M_WAIT, MT_SONAME);
236        (void) soaccept(so, nam);
237        if (name) {
238                 /* check length before it is destroyed */
239                if (*namelen > nam->m_len)
240                        *namelen = nam->m_len;
241                memcpy (name, mtod(nam, caddr_t), *namelen);
242        }
243        m_freem(nam);
244        rtems_bsdnet_semaphore_release ();
245        return (fd);
246
247}
248
249/*
250 * All `transmit' operations end up calling this routine.
251 */
252ssize_t
253sendmsg (int s, const struct msghdr *mp, int flags)
254{
255        int ret = -1;
256        int error;
257        struct uio auio;
258        struct iovec *iov;
259        struct socket *so;
260        struct mbuf *to, *control;
261        int i;
262        int len;
263
264        rtems_bsdnet_semaphore_obtain ();
265        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
266                rtems_bsdnet_semaphore_release ();
267                return -1;
268        }
269        auio.uio_iov = mp->msg_iov;
270        auio.uio_iovcnt = mp->msg_iovlen;
271        auio.uio_segflg = UIO_USERSPACE;
272        auio.uio_rw = UIO_WRITE;
273        auio.uio_offset = 0;
274        auio.uio_resid = 0;
275        iov = mp->msg_iov;
276        for (i = 0; i < mp->msg_iovlen; i++, iov++) {
277                if ((auio.uio_resid += iov->iov_len) < 0) {
278                        errno = EINVAL;
279                        rtems_bsdnet_semaphore_release ();
280                        return -1;
281                }
282        }
283        if (mp->msg_name) {
284                error = sockargstombuf (&to, mp->msg_name, mp->msg_namelen, MT_SONAME);
285                if (error) {
286                        errno = error;
287                        rtems_bsdnet_semaphore_release ();
288                        return -1;
289                }
290        }
291        else {
292                to = NULL;
293        }
294        if (mp->msg_control) {
295                if (mp->msg_controllen < sizeof (struct cmsghdr)) {
296                        errno = EINVAL;
297                        if (to)
298                                m_freem(to);
299                        rtems_bsdnet_semaphore_release ();
300                        return -1;
301                }
302                sockargstombuf (&control, mp->msg_control, mp->msg_controllen, MT_CONTROL);
303        }
304        else {
305                control = NULL;
306        }
307        len = auio.uio_resid;
308        error = sosend (so, to, &auio, (struct mbuf *)0, control, flags);
309        if (error) {
310                if (auio.uio_resid != len && (error == EINTR || error == EWOULDBLOCK))
311                        error = 0;
312        }
313        if (error)
314                errno = error;
315        else
316                ret = len - auio.uio_resid;
317        if (to)
318                m_freem(to);
319        rtems_bsdnet_semaphore_release ();
320        return (ret);
321}
322
323/*
324 * Send a message to a host
325 */
326ssize_t
327sendto (int s, const void *buf, size_t buflen, int flags, const struct sockaddr *to, int tolen)
328{
329        struct msghdr msg;
330        struct iovec iov;
331
332        iov.iov_base = (void *)buf;
333        iov.iov_len = buflen;
334        msg.msg_name = (caddr_t)to;
335        msg.msg_namelen = tolen;
336        msg.msg_iov = &iov;
337        msg.msg_iovlen = 1;
338        msg.msg_control = NULL;
339        msg.msg_controllen = 0;
340        return sendmsg (s, &msg, flags);
341}
342
343/*
344 * Send a message to a connected host
345 */
346ssize_t
347send (int s, const void *buf, size_t buflen, int flags)
348{
349        return sendto (s, buf, buflen, flags, NULL, 0);
350}
351
352/*
353 * All `receive' operations end up calling this routine.
354 */
355ssize_t
356recvmsg (int s, struct msghdr *mp, int flags)
357{
358        int ret = -1;
359        int error;
360        struct uio auio;
361        struct iovec *iov;
362        struct socket *so;
363        struct mbuf *from = NULL, *control = NULL;
364        int i;
365        int len;
366
367        rtems_bsdnet_semaphore_obtain ();
368        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
369                rtems_bsdnet_semaphore_release ();
370                return -1;
371        }
372        auio.uio_iov = mp->msg_iov;
373        auio.uio_iovcnt = mp->msg_iovlen;
374        auio.uio_segflg = UIO_USERSPACE;
375        auio.uio_rw = UIO_READ;
376        auio.uio_offset = 0;
377        auio.uio_resid = 0;
378        iov = mp->msg_iov;
379        for (i = 0; i < mp->msg_iovlen; i++, iov++) {
380                if ((auio.uio_resid += iov->iov_len) < 0) {
381                        errno = EINVAL;
382                        rtems_bsdnet_semaphore_release ();
383                        return -1;
384                }
385        }
386        len = auio.uio_resid;
387        mp->msg_flags = flags;
388        error = soreceive (so, &from, &auio, (struct mbuf **)NULL,
389                        mp->msg_control ? &control : (struct mbuf **)NULL,
390                        &mp->msg_flags);
391        if (error) {
392                if (auio.uio_resid != len && (error == EINTR || error == EWOULDBLOCK))
393                        error = 0;
394        }
395        if (error) {
396                errno = error;
397        }
398        else {
399                ret = len - auio.uio_resid;
400                if (mp->msg_name) {
401                        len = mp->msg_namelen;
402                        if ((len <= 0) || (from == NULL)) {
403                                len = 0;
404                        }
405                        else {
406                                if (len > from->m_len)
407                                        len = from->m_len;
408                                memcpy (mp->msg_name, mtod(from, caddr_t), len);
409                        }
410                        mp->msg_namelen = len;
411                }
412                if (mp->msg_control) {
413                        struct mbuf *m;
414                        caddr_t ctlbuf;
415
416                        len = mp->msg_controllen;
417                        m = control;
418                        mp->msg_controllen = 0;
419                        ctlbuf = (caddr_t) mp->msg_control;
420
421                        while (m && (len > 0)) {
422                                unsigned int tocopy;
423
424                                if (len >= m->m_len)
425                                        tocopy = m->m_len;
426                                else {
427                                        mp->msg_flags |= MSG_CTRUNC;
428                                        tocopy = len;
429                                }
430                                memcpy(ctlbuf, mtod(m, caddr_t), tocopy);
431                                ctlbuf += tocopy;
432                                len -= tocopy;
433                                m = m->m_next;
434                        }
435                        mp->msg_controllen = ctlbuf - mp->msg_control;
436                }
437        }
438        if (from)
439                m_freem (from);
440        if (control)
441                m_freem (control);
442        rtems_bsdnet_semaphore_release ();
443        return (ret);
444}
445
446/*
447 * Receive a message from a host
448 */
449ssize_t
450recvfrom (int s, void *buf, size_t buflen, int flags, const struct sockaddr *from, int *fromlen)
451{
452        struct msghdr msg;
453        struct iovec iov;
454        int ret;
455
456        iov.iov_base = buf;
457        iov.iov_len = buflen;
458        msg.msg_name = (caddr_t)from;
459        if (fromlen)
460                msg.msg_namelen = *fromlen;
461        else
462        msg.msg_namelen = 0;
463        msg.msg_iov = &iov;
464        msg.msg_iovlen = 1;
465        msg.msg_control = NULL;
466        msg.msg_controllen = 0;
467        ret = recvmsg (s, &msg, flags);
468        if ((from != NULL) && (fromlen != NULL) && (ret >= 0))
469                *fromlen = msg.msg_namelen;
470        return ret;
471}
472
473/*
474 * Receive a message from a connected host
475 */
476ssize_t
477recv (int s, void *buf, size_t buflen, int flags)
478{
479        return recvfrom (s, buf, buflen, flags, NULL, NULL);
480}
481
482int
483setsockopt (int s, int level, int name, const void *val, int len)
484{
485        struct socket *so;
486        struct mbuf *m = NULL;
487        int error;
488
489        rtems_bsdnet_semaphore_obtain ();
490        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
491                rtems_bsdnet_semaphore_release ();
492                return -1;
493        }
494        if (len > MLEN) {
495                errno = EINVAL;
496                rtems_bsdnet_semaphore_release ();
497                return -1;
498        }
499        if (val) {
500                error = sockargstombuf (&m, val, len, MT_SOOPTS);
501                if (error) {
502                        errno = error;
503                        rtems_bsdnet_semaphore_release ();
504                        return -1;
505                }
506        }
507        error = sosetopt(so, level, name, m);
508        if (error) {
509                errno = error;
510                rtems_bsdnet_semaphore_release ();
511                return -1;
512        }
513        rtems_bsdnet_semaphore_release ();
514        return 0;
515}
516
517int
518getsockopt (int s, int level, int name, void *aval, int *avalsize)
519{
520        struct socket *so;
521        struct mbuf *m = NULL, *m0;
522        char *val = aval;
523        int i, op, valsize;
524        int error;
525
526        rtems_bsdnet_semaphore_obtain ();
527        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
528                rtems_bsdnet_semaphore_release ();
529                return -1;
530        }
531        if (val)
532                valsize = *avalsize;
533        else
534                valsize = 0;
535        if (((error = sogetopt(so, level, name, &m)) == 0) && val && valsize && m) {
536                op = 0;
537                while (m && op < valsize) {
538                        i = valsize - op;
539                        if (i > m->m_len)
540                                i = m->m_len;
541                        memcpy (val, mtod(m, caddr_t), i);
542                        op += i;
543                        val += i;
544                        m0 = m;
545                        MFREE (m0, m);
546                }
547                *avalsize = op;
548        }
549        if (m != NULL)
550                (void) m_free(m);
551        if (error) {
552                errno = error;
553                rtems_bsdnet_semaphore_release ();
554                return -1;
555        }
556        rtems_bsdnet_semaphore_release ();
557        return 0;
558}
559
560static int
561getpeersockname (int s, struct sockaddr *name, int *namelen, int pflag)
562{
563        struct socket *so;
564        struct mbuf *m;
565        int len = *namelen;
566        int error;
567
568        rtems_bsdnet_semaphore_obtain ();
569        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
570                rtems_bsdnet_semaphore_release ();
571                return -1;
572        }
573        m = m_getclr(M_WAIT, MT_SONAME);
574        if (m == NULL) {
575                errno = ENOBUFS;
576                rtems_bsdnet_semaphore_release ();
577                return -1;
578        }
579        if (pflag)
580                error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, m);
581        else
582                error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, m);
583        if (error) {
584                errno = error;
585                rtems_bsdnet_semaphore_release ();
586                return -1;
587        }
588        if (len > m->m_len) {
589                len = m->m_len;
590                *namelen = len;
591        }
592        memcpy (name, mtod(m, caddr_t), len);
593        m_freem (m);
594        rtems_bsdnet_semaphore_release ();
595        return 0;
596}
597
598int
599getpeername (int s, struct sockaddr *name, int *namelen)
600{
601        return getpeersockname (s, name, namelen, 1);
602}
603int
604getsockname (int s, struct sockaddr *name, int *namelen)
605{
606        return getpeersockname (s, name, namelen, 0);
607}
608
609/*
610 ************************************************************************
611 *                      RTEMS I/O HANDLER ROUTINES                      *
612 ************************************************************************
613 */
614static int
615rtems_bsdnet_close (rtems_libio_t *iop)
616{
617        struct socket *so;
618        int error;
619
620        rtems_bsdnet_semaphore_obtain ();
621        if ((so = iop->data1) == NULL) {
622                errno = EBADF;
623                rtems_bsdnet_semaphore_release ();
624                return -1;
625        }
626        error = soclose (so);
627        rtems_bsdnet_semaphore_release ();
628        if (error) {
629                errno = error;
630                return -1;
631        }
632        return 0;
633}
634
635static int
636rtems_bsdnet_read (rtems_libio_t *iop, void *buffer, unsigned32 count)
637{
638        return recv (iop->data0, buffer, count, 0);
639}
640
641static int
642rtems_bsdnet_write (rtems_libio_t *iop, const void *buffer, unsigned32 count)
643{
644        return send (iop->data0, buffer, count, 0);
645}
646
647static int
648so_ioctl (rtems_libio_t *iop, struct socket *so, unsigned32 command, void *buffer)
649{
650        switch (command) {
651        case FIONBIO:
652                if (*(int *)buffer) {
653                        iop->flags |= O_NONBLOCK;
654                        so->so_state |= SS_NBIO;
655                }
656                else {
657                        iop->flags &= ~O_NONBLOCK;
658                        so->so_state &= ~SS_NBIO;
659                }
660                return 0;
661
662        case FIONREAD:
663                *(int *)buffer = so->so_rcv.sb_cc;
664                return 0;
665        }
666
667        if (IOCGROUP(command) == 'i')
668                return ifioctl (so, command, buffer, NULL);
669        if (IOCGROUP(command) == 'r')
670                return rtioctl (command, buffer, NULL);
671        return (*so->so_proto->pr_usrreqs->pru_control)(so, command, buffer, 0);
672}
673
674static int
675rtems_bsdnet_ioctl (rtems_libio_t *iop, unsigned32 command, void *buffer)
676{
677        struct socket *so;
678        int error;
679
680        rtems_bsdnet_semaphore_obtain ();
681        if ((so = iop->data1) == NULL) {
682                errno = EBADF;
683                rtems_bsdnet_semaphore_release ();
684                return -1;
685        }
686        error = so_ioctl (iop, so, command, buffer);
687        rtems_bsdnet_semaphore_release ();
688        if (error) {
689                errno = error;
690                return -1;
691        }
692        return 0;
693}
694
695static int
696rtems_bsdnet_fcntl (int cmd, rtems_libio_t *iop)
697{
698        struct socket *so;
699
700        if (cmd == F_SETFL) {
701                rtems_bsdnet_semaphore_obtain ();
702                if ((so = iop->data1) == NULL) {
703                        rtems_bsdnet_semaphore_release ();
704                        return EBADF;
705                }
706                if (iop->flags & O_NONBLOCK)
707                        so->so_state |= SS_NBIO;
708                else
709                        so->so_state &= ~SS_NBIO;
710                rtems_bsdnet_semaphore_release ();
711        }
712        return 0;
713}
714
715static int
716rtems_bsdnet_fstat (rtems_filesystem_location_info_t *loc, struct stat *sp)
717{
718        sp->st_mode = S_IFSOCK;
719        return 0;
720}
721
722static const rtems_filesystem_file_handlers_r socket_handlers = {
723        NULL,                   /* open */
724        rtems_bsdnet_close,     /* close */
725        rtems_bsdnet_read,      /* read */
726        rtems_bsdnet_write,     /* write */
727        rtems_bsdnet_ioctl,     /* ioctl */
728        NULL,                   /* lseek */
729        rtems_bsdnet_fstat,     /* fstat */
730        NULL,                   /* fchmod */
731        NULL,                   /* ftruncate */
732        NULL,                   /* fpathconf */
733        NULL,                   /* fsync */
734        NULL,                   /* fdatasync */
735        rtems_bsdnet_fcntl,     /* fcntl */
736};
Note: See TracBrowser for help on using the repository browser.