source: rtems/cpukit/libnetworking/rtems/rtems_syscall.c @ bdcf02d4

4.104.114.84.95
Last change on this file since bdcf02d4 was bdcf02d4, checked in by Joel Sherrill <joel.sherrill@…>, on Sep 5, 2000 at 3:47:44 PM

2000-09-05 Joel Sherrill <joel@…>

  • rtems/rtems_syscall.c: Changed from O_NONBLOCK to internal RTEMS_LIBIO_FLAGS_NO_DELAY to avoid O_NONBLOCK/O_NDELAY confusion and to work with the converted flags.
  • Property mode set to 100644
File size: 15.7 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                goto bad;
141        if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
142                m_freem(nam);
143                errno = EINPROGRESS;
144                rtems_bsdnet_semaphore_release ();
145                return -1;
146        }
147        while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
148                error = soconnsleep (so);
149                if (error)
150                        break;
151        }
152        if (error == 0) {
153                error = so->so_error;
154                so->so_error = 0;
155        }
156    bad:
157        so->so_state &= ~SS_ISCONNECTING;
158        m_freem (nam);
159        if (error)
160                errno = error;
161        else
162                ret = 0;
163        rtems_bsdnet_semaphore_release ();
164        return ret;
165}
166
167int
168listen (int s, int backlog)
169{
170        int error;
171        int ret = -1;
172        struct socket *so;
173
174        rtems_bsdnet_semaphore_obtain ();
175        if ((so = rtems_bsdnet_fdToSocket (s)) != NULL) {
176                error = solisten (so, backlog);
177                if (error == 0)
178                        ret = 0;
179                else
180                        errno = error;
181        }
182        rtems_bsdnet_semaphore_release ();
183        return ret;
184}
185
186int
187accept (int s, struct sockaddr *name, int *namelen)
188{
189        int fd;
190        struct socket *head, *so;
191        struct mbuf *nam;
192
193        rtems_bsdnet_semaphore_obtain ();
194        if ((head = rtems_bsdnet_fdToSocket (s)) == NULL) {
195                rtems_bsdnet_semaphore_release ();
196                return -1;
197        }
198        if ((head->so_options & SO_ACCEPTCONN) == 0) {
199                errno = EINVAL;
200                rtems_bsdnet_semaphore_release ();
201                return -1;
202        }
203        if ((head->so_state & SS_NBIO) && head->so_comp.tqh_first == NULL) {
204                errno = EWOULDBLOCK;
205                rtems_bsdnet_semaphore_release ();
206                return -1;
207        }
208        while (head->so_comp.tqh_first == NULL && head->so_error == 0) {
209                if (head->so_state & SS_CANTRCVMORE) {
210                        head->so_error = ECONNABORTED;
211                        break;
212                }
213                head->so_error = soconnsleep (head);
214        }
215        if (head->so_error) {
216                errno = head->so_error;
217                head->so_error = 0;
218                rtems_bsdnet_semaphore_release ();
219                return -1;
220        }
221
222        so = head->so_comp.tqh_first;
223        TAILQ_REMOVE(&head->so_comp, so, so_list);
224        head->so_qlen--;
225
226        fd = rtems_bsdnet_makeFdForSocket (so, &socket_handlers);
227        if (fd < 0) {
228                TAILQ_INSERT_HEAD(&head->so_comp, so, so_list);
229                head->so_qlen++;
230                soconnwakeup (head);
231                rtems_bsdnet_semaphore_release ();
232                return -1;
233        }
234        so->so_state &= ~SS_COMP;
235        so->so_head = NULL;
236
237        nam = m_get(M_WAIT, MT_SONAME);
238        (void) soaccept(so, nam);
239        if (name) {
240                 /* check length before it is destroyed */
241                if (*namelen > nam->m_len)
242                        *namelen = nam->m_len;
243                memcpy (name, mtod(nam, caddr_t), *namelen);
244        }
245        m_freem(nam);
246        rtems_bsdnet_semaphore_release ();
247        return (fd);
248
249}
250
251/*
252 *  Shutdown routine
253 */
254
255int
256shutdown (int s, int how)
257{
258      struct socket *so;
259      int error;
260
261      rtems_bsdnet_semaphore_obtain ();
262      if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
263              rtems_bsdnet_semaphore_release ();
264              return -1;
265      }
266      error = soshutdown(so, how);
267      rtems_bsdnet_semaphore_release ();
268      if (error) {
269              errno = error;
270              return -1;
271      }
272      return 0;
273}
274
275/*
276 * All `transmit' operations end up calling this routine.
277 */
278ssize_t
279sendmsg (int s, const struct msghdr *mp, int flags)
280{
281        int ret = -1;
282        int error;
283        struct uio auio;
284        struct iovec *iov;
285        struct socket *so;
286        struct mbuf *to, *control;
287        int i;
288        int len;
289
290        rtems_bsdnet_semaphore_obtain ();
291        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
292                rtems_bsdnet_semaphore_release ();
293                return -1;
294        }
295        auio.uio_iov = mp->msg_iov;
296        auio.uio_iovcnt = mp->msg_iovlen;
297        auio.uio_segflg = UIO_USERSPACE;
298        auio.uio_rw = UIO_WRITE;
299        auio.uio_offset = 0;
300        auio.uio_resid = 0;
301        iov = mp->msg_iov;
302        for (i = 0; i < mp->msg_iovlen; i++, iov++) {
303                if ((auio.uio_resid += iov->iov_len) < 0) {
304                        errno = EINVAL;
305                        rtems_bsdnet_semaphore_release ();
306                        return -1;
307                }
308        }
309        if (mp->msg_name) {
310                error = sockargstombuf (&to, mp->msg_name, mp->msg_namelen, MT_SONAME);
311                if (error) {
312                        errno = error;
313                        rtems_bsdnet_semaphore_release ();
314                        return -1;
315                }
316        }
317        else {
318                to = NULL;
319        }
320        if (mp->msg_control) {
321                if (mp->msg_controllen < sizeof (struct cmsghdr)) {
322                        errno = EINVAL;
323                        if (to)
324                                m_freem(to);
325                        rtems_bsdnet_semaphore_release ();
326                        return -1;
327                }
328                sockargstombuf (&control, mp->msg_control, mp->msg_controllen, MT_CONTROL);
329        }
330        else {
331                control = NULL;
332        }
333        len = auio.uio_resid;
334        error = sosend (so, to, &auio, (struct mbuf *)0, control, flags);
335        if (error) {
336                if (auio.uio_resid != len && (error == EINTR || error == EWOULDBLOCK))
337                        error = 0;
338        }
339        if (error) 
340                errno = error;
341        else
342                ret = len - auio.uio_resid;
343        if (to)
344                m_freem(to);
345        rtems_bsdnet_semaphore_release ();
346        return (ret);
347}
348
349/*
350 * Send a message to a host
351 */
352ssize_t
353sendto (int s, const void *buf, size_t buflen, int flags, const struct sockaddr *to, int tolen)
354{
355        struct msghdr msg;
356        struct iovec iov;
357
358        iov.iov_base = (void *)buf;
359        iov.iov_len = buflen;
360        msg.msg_name = (caddr_t)to;
361        msg.msg_namelen = tolen;
362        msg.msg_iov = &iov;
363        msg.msg_iovlen = 1;
364        msg.msg_control = NULL;
365        msg.msg_controllen = 0;
366        return sendmsg (s, &msg, flags);
367}
368
369/*
370 * Send a message to a connected host
371 */
372ssize_t
373send (int s, const void *buf, size_t buflen, int flags)
374{
375        return sendto (s, buf, buflen, flags, NULL, 0);
376}
377
378/*
379 * All `receive' operations end up calling this routine.
380 */
381ssize_t
382recvmsg (int s, struct msghdr *mp, int flags)
383{
384        int ret = -1;
385        int error;
386        struct uio auio;
387        struct iovec *iov;
388        struct socket *so;
389        struct mbuf *from = NULL, *control = NULL;
390        int i;
391        int len;
392
393        rtems_bsdnet_semaphore_obtain ();
394        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
395                rtems_bsdnet_semaphore_release ();
396                return -1;
397        }
398        auio.uio_iov = mp->msg_iov;
399        auio.uio_iovcnt = mp->msg_iovlen;
400        auio.uio_segflg = UIO_USERSPACE;
401        auio.uio_rw = UIO_READ;
402        auio.uio_offset = 0;
403        auio.uio_resid = 0;
404        iov = mp->msg_iov;
405        for (i = 0; i < mp->msg_iovlen; i++, iov++) {
406                if ((auio.uio_resid += iov->iov_len) < 0) {
407                        errno = EINVAL;
408                        rtems_bsdnet_semaphore_release ();
409                        return -1;
410                }
411        }
412        len = auio.uio_resid;
413        mp->msg_flags = flags;
414        error = soreceive (so, &from, &auio, (struct mbuf **)NULL, 
415                        mp->msg_control ? &control : (struct mbuf **)NULL,
416                        &mp->msg_flags);
417        if (error) {
418                if (auio.uio_resid != len && (error == EINTR || error == EWOULDBLOCK))
419                        error = 0;
420        }
421        if (error) {
422                errno = error;
423        }
424        else {
425                ret = len - auio.uio_resid;
426                if (mp->msg_name) {
427                        len = mp->msg_namelen;
428                        if ((len <= 0) || (from == NULL)) {
429                                len = 0;
430                        }
431                        else {
432                                if (len > from->m_len)
433                                        len = from->m_len;
434                                memcpy (mp->msg_name, mtod(from, caddr_t), len);
435                        }
436                        mp->msg_namelen = len;
437                }
438                if (mp->msg_control) {
439                        struct mbuf *m;
440                        caddr_t ctlbuf;
441
442                        len = mp->msg_controllen;
443                        m = control;
444                        mp->msg_controllen = 0;
445                        ctlbuf = (caddr_t) mp->msg_control;
446
447                        while (m && (len > 0)) {
448                                unsigned int tocopy;
449
450                                if (len >= m->m_len) 
451                                        tocopy = m->m_len;
452                                else {
453                                        mp->msg_flags |= MSG_CTRUNC;
454                                        tocopy = len;
455                                }
456                                memcpy(ctlbuf, mtod(m, caddr_t), tocopy);
457                                ctlbuf += tocopy;
458                                len -= tocopy;
459                                m = m->m_next;
460                        }
461                        mp->msg_controllen = ctlbuf - mp->msg_control;
462                }
463        }
464        if (from)
465                m_freem (from);
466        if (control)
467                m_freem (control);
468        rtems_bsdnet_semaphore_release ();
469        return (ret);
470}
471
472/*
473 * Receive a message from a host
474 */
475ssize_t
476recvfrom (int s, void *buf, size_t buflen, int flags, const struct sockaddr *from, int *fromlen)
477{
478        struct msghdr msg;
479        struct iovec iov;
480        int ret;
481
482        iov.iov_base = buf;
483        iov.iov_len = buflen;
484        msg.msg_name = (caddr_t)from;
485        if (fromlen)
486                msg.msg_namelen = *fromlen;
487        else
488        msg.msg_namelen = 0;
489        msg.msg_iov = &iov;
490        msg.msg_iovlen = 1;
491        msg.msg_control = NULL;
492        msg.msg_controllen = 0;
493        ret = recvmsg (s, &msg, flags);
494        if ((from != NULL) && (fromlen != NULL) && (ret >= 0))
495                *fromlen = msg.msg_namelen;
496        return ret;
497}
498
499/*
500 * Receive a message from a connected host
501 */
502ssize_t
503recv (int s, void *buf, size_t buflen, int flags)
504{
505        return recvfrom (s, buf, buflen, flags, NULL, NULL);
506}
507
508int
509setsockopt (int s, int level, int name, const void *val, int len)
510{
511        struct socket *so;
512        struct mbuf *m = NULL;
513        int error;
514
515        rtems_bsdnet_semaphore_obtain ();
516        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
517                rtems_bsdnet_semaphore_release ();
518                return -1;
519        }
520        if (len > MLEN) {
521                errno = EINVAL;
522                rtems_bsdnet_semaphore_release ();
523                return -1;
524        }
525        if (val) {
526                error = sockargstombuf (&m, val, len, MT_SOOPTS);
527                if (error) {
528                        errno = error;
529                        rtems_bsdnet_semaphore_release ();
530                        return -1;
531                }
532        }
533        error = sosetopt(so, level, name, m);
534        if (error) {
535                errno = error;
536                rtems_bsdnet_semaphore_release ();
537                return -1;
538        }
539        rtems_bsdnet_semaphore_release ();
540        return 0;
541}
542
543int
544getsockopt (int s, int level, int name, void *aval, int *avalsize)
545{
546        struct socket *so;
547        struct mbuf *m = NULL, *m0;
548        char *val = aval;
549        int i, op, valsize;
550        int error;
551
552        rtems_bsdnet_semaphore_obtain ();
553        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
554                rtems_bsdnet_semaphore_release ();
555                return -1;
556        }
557        if (val)
558                valsize = *avalsize;
559        else
560                valsize = 0;
561        if (((error = sogetopt(so, level, name, &m)) == 0) && val && valsize && m) {
562                op = 0;
563                while (m && op < valsize) {
564                        i = valsize - op;
565                        if (i > m->m_len)
566                                i = m->m_len;
567                        memcpy (val, mtod(m, caddr_t), i);
568                        op += i;
569                        val += i;
570                        m0 = m;
571                        MFREE (m0, m);
572                }
573                *avalsize = op;
574        }
575        if (m != NULL)
576                (void) m_free(m);
577        if (error) {
578                errno = error;
579                rtems_bsdnet_semaphore_release ();
580                return -1;
581        }
582        rtems_bsdnet_semaphore_release ();
583        return 0;
584}
585
586static int
587getpeersockname (int s, struct sockaddr *name, int *namelen, int pflag)
588{
589        struct socket *so;
590        struct mbuf *m;
591        int len = *namelen;
592        int error;
593
594        rtems_bsdnet_semaphore_obtain ();
595        if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) {
596                rtems_bsdnet_semaphore_release ();
597                return -1;
598        }
599        m = m_getclr(M_WAIT, MT_SONAME);
600        if (m == NULL) {
601                errno = ENOBUFS;
602                rtems_bsdnet_semaphore_release ();
603                return -1;
604        }
605        if (pflag)
606                error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, m);
607        else
608                error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, m);
609        if (error) {
610                m_freem(m);
611                errno = error;
612                rtems_bsdnet_semaphore_release ();
613                return -1;
614        }
615        if (len > m->m_len) {
616                len = m->m_len;
617                *namelen = len;
618        }
619        memcpy (name, mtod(m, caddr_t), len);
620        m_freem (m);
621        rtems_bsdnet_semaphore_release ();
622        return 0;
623}
624
625int
626getpeername (int s, struct sockaddr *name, int *namelen)
627{
628        return getpeersockname (s, name, namelen, 1);
629}
630int
631getsockname (int s, struct sockaddr *name, int *namelen)
632{
633        return getpeersockname (s, name, namelen, 0);
634}
635
636/*
637 ************************************************************************
638 *                      RTEMS I/O HANDLER ROUTINES                      *
639 ************************************************************************
640 */
641static int
642rtems_bsdnet_close (rtems_libio_t *iop)
643{
644        struct socket *so;
645        int error;
646
647        rtems_bsdnet_semaphore_obtain ();
648        if ((so = iop->data1) == NULL) {
649                errno = EBADF;
650                rtems_bsdnet_semaphore_release ();
651                return -1;
652        }
653        error = soclose (so);
654        rtems_bsdnet_semaphore_release ();
655        if (error) {
656                errno = error;
657                return -1;
658        }
659        return 0;
660}
661
662static int
663rtems_bsdnet_read (rtems_libio_t *iop, void *buffer, unsigned32 count)
664{
665        return recv (iop->data0, buffer, count, 0);
666}
667
668static int
669rtems_bsdnet_write (rtems_libio_t *iop, const void *buffer, unsigned32 count)
670{
671        return send (iop->data0, buffer, count, 0);
672}
673
674static int
675so_ioctl (rtems_libio_t *iop, struct socket *so, unsigned32 command, void *buffer)
676{
677        switch (command) {
678        case FIONBIO:
679                if (*(int *)buffer) {
680                        iop->flags |= O_NONBLOCK;
681                        so->so_state |= SS_NBIO;
682                }
683                else {
684                        iop->flags &= ~O_NONBLOCK;
685                        so->so_state &= ~SS_NBIO;
686                }
687                return 0;
688
689        case FIONREAD:
690                *(int *)buffer = so->so_rcv.sb_cc;
691                return 0;
692        }
693
694        if (IOCGROUP(command) == 'i')
695                return ifioctl (so, command, buffer, NULL);
696        if (IOCGROUP(command) == 'r')
697                return rtioctl (command, buffer, NULL);
698        return (*so->so_proto->pr_usrreqs->pru_control)(so, command, buffer, 0);
699}
700
701static int
702rtems_bsdnet_ioctl (rtems_libio_t *iop, unsigned32 command, void *buffer)
703{
704        struct socket *so;
705        int error;
706
707        rtems_bsdnet_semaphore_obtain ();
708        if ((so = iop->data1) == NULL) {
709                errno = EBADF;
710                rtems_bsdnet_semaphore_release ();
711                return -1;
712        }
713        error = so_ioctl (iop, so, command, buffer);
714        rtems_bsdnet_semaphore_release ();
715        if (error) {
716                errno = error;
717                return -1;
718        }
719        return 0;
720}
721
722static int
723rtems_bsdnet_fcntl (int cmd, rtems_libio_t *iop)
724{
725        struct socket *so;
726
727        if (cmd == F_SETFL) {
728                rtems_bsdnet_semaphore_obtain ();
729                if ((so = iop->data1) == NULL) {
730                        rtems_bsdnet_semaphore_release ();
731                        return EBADF;
732                }
733                if (iop->flags & LIBIO_FLAGS_NO_DELAY)
734                        so->so_state |= SS_NBIO;
735                else
736                        so->so_state &= ~SS_NBIO;
737                rtems_bsdnet_semaphore_release ();
738        }
739        return 0;
740}
741
742static int
743rtems_bsdnet_fstat (rtems_filesystem_location_info_t *loc, struct stat *sp)
744{
745        sp->st_mode = S_IFSOCK;
746        return 0;
747}
748
749static const rtems_filesystem_file_handlers_r socket_handlers = {
750        NULL,                   /* open */
751        rtems_bsdnet_close,     /* close */
752        rtems_bsdnet_read,      /* read */
753        rtems_bsdnet_write,     /* write */
754        rtems_bsdnet_ioctl,     /* ioctl */
755        NULL,                   /* lseek */
756        rtems_bsdnet_fstat,     /* fstat */
757        NULL,                   /* fchmod */
758        NULL,                   /* ftruncate */
759        NULL,                   /* fpathconf */
760        NULL,                   /* fsync */
761        NULL,                   /* fdatasync */
762        rtems_bsdnet_fcntl,     /* fcntl */
763};
Note: See TracBrowser for help on using the repository browser.