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

4.104.114.84.95
Last change on this file since cca4400 was cca4400, checked in by Joel Sherrill <joel.sherrill@…>, on Dec 10, 1998 at 11:31:54 PM

Merged Eric Norum's select patch that was based on 4.0 and resolved
all conflicts.

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