1 | #undef NDEBUG
|
---|
2 |
|
---|
3 | #include <assert.h>
|
---|
4 | #include <errno.h>
|
---|
5 | #include <stdio.h>
|
---|
6 | #include <stdlib.h>
|
---|
7 | #include <string.h>
|
---|
8 | #include <unistd.h>
|
---|
9 | #include <sys/ioctl.h>
|
---|
10 | #include <sys/socket.h>
|
---|
11 | #include <netinet/in.h>
|
---|
12 |
|
---|
13 | #include <net/gen/in.h>
|
---|
14 | #include <net/gen/udp.h>
|
---|
15 | #include <net/gen/udp_hdr.h>
|
---|
16 | #include <net/gen/udp_io.h>
|
---|
17 |
|
---|
18 | #define DEBUG 0
|
---|
19 |
|
---|
20 | static ssize_t _udp_sendto(int socket, const void *message, size_t length,
|
---|
21 | int flags, const struct sockaddr *dest_addr, socklen_t dest_len,
|
---|
22 | nwio_udpopt_t *udpoptp);
|
---|
23 |
|
---|
24 | ssize_t sendto(int socket, const void *message, size_t length, int flags,
|
---|
25 | const struct sockaddr *dest_addr, socklen_t dest_len)
|
---|
26 | {
|
---|
27 | int r;
|
---|
28 | nwio_udpopt_t udpopt;
|
---|
29 |
|
---|
30 | r= ioctl(socket, NWIOGUDPOPT, &udpopt);
|
---|
31 | if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
---|
32 | {
|
---|
33 | if (r == -1)
|
---|
34 | return r;
|
---|
35 | return _udp_sendto(socket, message, length, flags,
|
---|
36 | dest_addr, dest_len, &udpopt);
|
---|
37 | }
|
---|
38 |
|
---|
39 | #if DEBUG
|
---|
40 | fprintf(stderr, "sendto: not implemented for fd %d\n", socket);
|
---|
41 | #endif
|
---|
42 | errno= ENOSYS;
|
---|
43 | return -1;
|
---|
44 | }
|
---|
45 |
|
---|
46 | static ssize_t _udp_sendto(int socket, const void *message, size_t length,
|
---|
47 | int flags, const struct sockaddr *dest_addr, socklen_t dest_len,
|
---|
48 | nwio_udpopt_t *udpoptp)
|
---|
49 | {
|
---|
50 | int r, t_errno;
|
---|
51 | size_t buflen;
|
---|
52 | void *buf;
|
---|
53 | struct sockaddr_in *sinp;
|
---|
54 | udp_io_hdr_t *io_hdrp;
|
---|
55 |
|
---|
56 | if (flags)
|
---|
57 | {
|
---|
58 | #if DEBUG
|
---|
59 | fprintf(stderr, "sendto(udp): flags not implemented\n");
|
---|
60 | #endif
|
---|
61 | errno= ENOSYS;
|
---|
62 | return -1;
|
---|
63 | }
|
---|
64 |
|
---|
65 | if (udpoptp->nwuo_flags & NWUO_RWDATONLY)
|
---|
66 | return write(socket, message, length);
|
---|
67 |
|
---|
68 | if ((udpoptp->nwuo_flags & NWUO_RP_ANY) ||
|
---|
69 | (udpoptp->nwuo_flags & NWUO_RA_ANY))
|
---|
70 | {
|
---|
71 | /* Check destination address */
|
---|
72 | if (dest_len < sizeof(*sinp))
|
---|
73 | {
|
---|
74 | errno= EINVAL;
|
---|
75 | return -1;
|
---|
76 | }
|
---|
77 | sinp= (struct sockaddr_in *)dest_addr;
|
---|
78 | if (sinp->sin_family != AF_INET)
|
---|
79 | {
|
---|
80 | errno= EAFNOSUPPORT;
|
---|
81 | return -1;
|
---|
82 | }
|
---|
83 | }
|
---|
84 |
|
---|
85 | buflen= sizeof(*io_hdrp) + length;
|
---|
86 | if (buflen < length)
|
---|
87 | {
|
---|
88 | /* Overflow */
|
---|
89 | errno= EMSGSIZE;
|
---|
90 | return -1;
|
---|
91 | }
|
---|
92 | buf= malloc(buflen);
|
---|
93 | if (buf == NULL)
|
---|
94 | return -1;
|
---|
95 |
|
---|
96 | io_hdrp= buf;
|
---|
97 | io_hdrp->uih_src_addr= 0; /* Unused */
|
---|
98 | io_hdrp->uih_src_port= 0; /* Will cause error if NWUO_LP_ANY */
|
---|
99 | if (udpoptp->nwuo_flags & NWUO_RA_ANY)
|
---|
100 | io_hdrp->uih_dst_addr= sinp->sin_addr.s_addr;
|
---|
101 | else
|
---|
102 | io_hdrp->uih_dst_addr= 0;
|
---|
103 | if (udpoptp->nwuo_flags & NWUO_RP_ANY)
|
---|
104 | io_hdrp->uih_dst_port= sinp->sin_port;
|
---|
105 | else
|
---|
106 | io_hdrp->uih_dst_port= 0;
|
---|
107 | io_hdrp->uih_ip_opt_len= 0;
|
---|
108 | io_hdrp->uih_data_len= 0;
|
---|
109 |
|
---|
110 | memcpy(&io_hdrp[1], message, length);
|
---|
111 | r= write(socket, buf, buflen);
|
---|
112 | if (r == -1)
|
---|
113 | {
|
---|
114 | t_errno= errno;
|
---|
115 | free(buf);
|
---|
116 | errno= t_errno;
|
---|
117 | return -1;
|
---|
118 | }
|
---|
119 | assert(r == buflen);
|
---|
120 | free(buf);
|
---|
121 | return length;
|
---|
122 | }
|
---|
123 |
|
---|