11 #include <sys/ioctl.h>
12 #include <sys/socket.h>
13 #include <netinet/in.h>
15 #include <net/gen/in.h>
16 #include <net/gen/ip_hdr.h>
17 #include <net/gen/ip_io.h>
18 #include <net/gen/tcp.h>
19 #include <net/gen/tcp_io.h>
20 #include <net/gen/udp.h>
21 #include <net/gen/udp_hdr.h>
22 #include <net/gen/udp_io.h>
26 static ssize_t
_tcp_sendto(int sock
, const void *message
, size_t length
,
27 int flags
, const struct sockaddr
*dest_addr
, socklen_t dest_len
);
28 static ssize_t
_udp_sendto(int sock
, const void *message
, size_t length
,
29 int flags
, const struct sockaddr
*dest_addr
, socklen_t dest_len
,
30 nwio_udpopt_t
*udpoptp
);
31 static ssize_t
_uds_sendto_conn(int sock
, const void *message
, size_t length
,
32 int flags
, const struct sockaddr
*dest_addr
, socklen_t dest_len
);
33 static ssize_t
_uds_sendto_dgram(int sock
, const void *message
, size_t length
,
34 int flags
, const struct sockaddr
*dest_addr
, socklen_t dest_len
);
37 * Send a message on a socket.
40 __sendto(int fd
, const void * buffer
, size_t length
, int flags
,
41 const struct sockaddr
* dest_addr
, socklen_t dest_len
)
45 memset(&m
, 0, sizeof(m
));
46 m
.m_lc_vfs_sendrecv
.fd
= fd
;
47 m
.m_lc_vfs_sendrecv
.buf
= (vir_bytes
)buffer
;
48 m
.m_lc_vfs_sendrecv
.len
= length
;
49 m
.m_lc_vfs_sendrecv
.flags
= flags
;
50 m
.m_lc_vfs_sendrecv
.addr
= (vir_bytes
)dest_addr
;
51 m
.m_lc_vfs_sendrecv
.addr_len
= dest_len
;
53 return _syscall(VFS_PROC_NR
, VFS_SENDTO
, &m
);
56 ssize_t
sendto(int sock
, const void *message
, size_t length
, int flags
,
57 const struct sockaddr
*dest_addr
, socklen_t dest_len
)
65 r
= __sendto(sock
, message
, length
, flags
, dest_addr
, dest_len
);
66 if (r
!= -1 || (errno
!= ENOTSOCK
&& errno
!= ENOSYS
))
69 /* For old socket driver implementations, this flag is the default. */
70 flags
&= ~MSG_NOSIGNAL
;
72 r
= ioctl(sock
, NWIOGTCPOPT
, &tcpopt
);
73 if (r
!= -1 || errno
!= ENOTTY
)
77 return _tcp_sendto(sock
, message
, length
, flags
,
81 r
= ioctl(sock
, NWIOGUDPOPT
, &udpopt
);
82 if (r
!= -1 || errno
!= ENOTTY
)
86 return _udp_sendto(sock
, message
, length
, flags
,
87 dest_addr
, dest_len
, &udpopt
);
90 r
= ioctl(sock
, NWIOGUDSSOTYPE
, &uds_sotype
);
91 if (r
!= -1 || errno
!= ENOTTY
)
97 if (uds_sotype
== SOCK_DGRAM
) {
99 return _uds_sendto_dgram(sock
, message
,
100 length
, flags
,dest_addr
, dest_len
);
103 return _uds_sendto_conn(sock
, message
,
104 length
, flags
, dest_addr
, dest_len
);
108 r
= ioctl(sock
, NWIOGIPOPT
, &ipopt
);
109 if (r
!= -1 || errno
!= ENOTTY
)
112 const struct sockaddr_in
*sinp
;
120 sinp
= (const struct sockaddr_in
*)dest_addr
;
121 if (sinp
->sin_family
!= AF_INET
)
128 /* XXX this is horrible: we have to copy the entire buffer
129 * because we have to change one header field. Obviously we
130 * can't modify the user buffer directly..
132 if ((ip_hdr
= malloc(length
)) == NULL
)
133 return -1; /* errno is ENOMEM */
134 memcpy(ip_hdr
, message
, length
);
135 ip_hdr
->ih_dst
= sinp
->sin_addr
.s_addr
;
137 retval
= write(sock
, ip_hdr
, length
);
149 static ssize_t
_tcp_sendto(int sock
, const void *message
, size_t length
,
150 int flags
, const struct sockaddr
*dest_addr
, socklen_t dest_len
)
155 fprintf(stderr
, "sendto(tcp): flags not implemented\n");
161 /* Silently ignore destination, if given. */
163 return write(sock
, message
, length
);
166 static ssize_t
_udp_sendto(int sock
, const void *message
, size_t length
,
167 int flags
, const struct sockaddr
*dest_addr
, socklen_t dest_len
,
168 nwio_udpopt_t
*udpoptp
)
173 struct sockaddr_in
*sinp
;
174 udp_io_hdr_t
*io_hdrp
;
179 fprintf(stderr
, "sendto(udp): flags not implemented\n");
185 if (udpoptp
->nwuo_flags
& NWUO_RWDATONLY
)
186 return write(sock
, message
, length
);
188 if ((udpoptp
->nwuo_flags
& NWUO_RP_ANY
) ||
189 (udpoptp
->nwuo_flags
& NWUO_RA_ANY
))
197 /* Check destination address */
198 if (dest_len
< sizeof(*sinp
))
203 sinp
= (struct sockaddr_in
*) __UNCONST(dest_addr
);
204 if (sinp
->sin_family
!= AF_INET
)
211 buflen
= sizeof(*io_hdrp
) + length
;
223 io_hdrp
->uih_src_addr
= 0; /* Unused */
224 io_hdrp
->uih_src_port
= 0; /* Will cause error if NWUO_LP_ANY */
225 if (udpoptp
->nwuo_flags
& NWUO_RA_ANY
)
226 io_hdrp
->uih_dst_addr
= sinp
->sin_addr
.s_addr
;
228 io_hdrp
->uih_dst_addr
= 0;
229 if (udpoptp
->nwuo_flags
& NWUO_RP_ANY
)
230 io_hdrp
->uih_dst_port
= sinp
->sin_port
;
232 io_hdrp
->uih_dst_port
= 0;
233 io_hdrp
->uih_ip_opt_len
= 0;
234 io_hdrp
->uih_data_len
= 0;
236 memcpy(&io_hdrp
[1], message
, length
);
237 r
= write(sock
, buf
, buflen
);
245 assert((size_t)r
== buflen
);
250 static ssize_t
_uds_sendto_conn(int sock
, const void *message
, size_t length
,
251 int flags
, const struct sockaddr
*dest_addr
, socklen_t dest_len
)
254 /* for connection oriented unix domain sockets (SOCK_STREAM /
260 fprintf(stderr
, "sendto(uds): flags not implemented\n");
266 /* Silently ignore destination, if given. */
268 return write(sock
, message
, length
);
271 static ssize_t
_uds_sendto_dgram(int sock
, const void *message
, size_t length
,
272 int flags
, const struct sockaddr
*dest_addr
, socklen_t dest_len
)
276 /* for connectionless unix domain sockets (SOCK_DGRAM) */
280 fprintf(stderr
, "sendto(uds): flags not implemented\n");
286 if (dest_addr
== NULL
) {
291 /* set the target address */
292 r
= ioctl(sock
, NWIOSUDSTADDR
, (void *) __UNCONST(dest_addr
));
298 return write(sock
, message
, length
);