source: rtems/c/src/exec/libnetworking/rtems/rtems_syscall.c @ 91b1c8e

4.104.114.84.95
Last change on this file since 91b1c8e was 91b1c8e, checked in by Joel Sherrill <joel.sherrill@…>, on Dec 7, 1998 at 5:42:52 PM

Patch from Ian Lance Taylor <ian@…>:

RTEMS permits using the SO_SNDTIMEO and SO_RCVTIMEO socket options to
set a timeout for most socket I/O operations. However, in RTEMS
4.0.0, those options do not affect connect or accept. I don't know of
any way to put a timeout on those calls in RTEMS 4.0.0; can anybody
point to one.

Since it is frequently useful to have a timeout on accept, and
sometimes useful to have a timeout on connect shorter than the BSD
system default of 75 seconds, the following patch causes SO_RCVTIMEO
to affect connect and accept.

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