source: rtems/c/src/exec/libnetworking/rtems/rtems_syscall.c @ 6a4096b

4.104.114.84.95
Last change on this file since 6a4096b was 6a4096b, checked in by Joel Sherrill <joel.sherrill@…>, on 03/30/99 at 15:40:29

Patch to add shutdown() routine from Tony R. Ambardar <tonya@…>.

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