source: rtems/c/src/exec/libnetworking/rtems/rtems_syscall.c @ 73f6236

4.104.114.84.95
Last change on this file since 73f6236 was 73f6236, checked in by Joel Sherrill <joel.sherrill@…>, on 03/01/99 at 22:40:08

Patch from Eric Norum <eric@…> to eliminate external
IO handlers scheme that was implemented originally just to support
sockets. The file system IO switch is more general and works fine.

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