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/tcp.h>
17 #include <net/gen/tcp_io.h>
18 #include <net/gen/udp.h>
19 #include <net/gen/udp_hdr.h>
20 #include <net/gen/udp_io.h>
22 #include <net/gen/ip_hdr.h>
23 #include <net/gen/ip_io.h>
27 static ssize_t
_tcp_recvfrom(int sock
, void *__restrict buffer
, size_t length
,
28 int flags
, struct sockaddr
*__restrict address
,
29 socklen_t
*__restrict address_len
, nwio_tcpconf_t
*tcpconfp
);
30 static ssize_t
_udp_recvfrom(int sock
, void *__restrict buffer
, size_t length
,
31 int flags
, struct sockaddr
*__restrict address
,
32 socklen_t
*__restrict address_len
, nwio_udpopt_t
*udpoptp
);
33 static ssize_t
_uds_recvfrom_conn(int sock
, void *__restrict buffer
,
34 size_t length
, int flags
, struct sockaddr
*__restrict address
,
35 socklen_t
*__restrict address_len
, struct sockaddr_un
*uds_addr
);
36 static ssize_t
_uds_recvfrom_dgram(int sock
, void *__restrict buffer
,
37 size_t length
, int flags
, struct sockaddr
*__restrict address
,
38 socklen_t
*__restrict address_len
);
41 * Receive a message from a socket.
44 __recvfrom(int fd
, void * __restrict buffer
, size_t length
, int flags
,
45 struct sockaddr
* __restrict address
,
46 socklen_t
* __restrict address_len
)
51 if (address
!= NULL
&& address_len
== NULL
) {
56 memset(&m
, 0, sizeof(m
));
57 m
.m_lc_vfs_sendrecv
.fd
= fd
;
58 m
.m_lc_vfs_sendrecv
.buf
= (vir_bytes
)buffer
;
59 m
.m_lc_vfs_sendrecv
.len
= length
;
60 m
.m_lc_vfs_sendrecv
.flags
= flags
;
61 m
.m_lc_vfs_sendrecv
.addr
= (vir_bytes
)address
;
62 m
.m_lc_vfs_sendrecv
.addr_len
= (address
!= NULL
) ? *address_len
: 0;
64 if ((r
= _syscall(VFS_PROC_NR
, VFS_RECVFROM
, &m
)) < 0)
68 *address_len
= m
.m_vfs_lc_socklen
.len
;
72 ssize_t
recvfrom(int sock
, void *__restrict buffer
, size_t length
,
73 int flags
, struct sockaddr
*__restrict address
,
74 socklen_t
*__restrict address_len
)
77 nwio_tcpconf_t tcpconf
;
80 struct sockaddr_un uds_addr
;
83 r
= __recvfrom(sock
, buffer
, length
, flags
, address
, address_len
);
84 if (r
!= -1 || (errno
!= ENOTSOCK
&& errno
!= ENOSYS
))
88 fprintf(stderr
, "recvfrom: for fd %d\n", sock
);
91 r
= ioctl(sock
, NWIOGTCPCONF
, &tcpconf
);
92 if (r
!= -1 || errno
!= ENOTTY
)
96 return _tcp_recvfrom(sock
, buffer
, length
, flags
,
97 address
, address_len
, &tcpconf
);
100 r
= ioctl(sock
, NWIOGUDPOPT
, &udpopt
);
101 if (r
!= -1 || errno
!= ENOTTY
)
105 return _udp_recvfrom(sock
, buffer
, length
, flags
,
106 address
, address_len
, &udpopt
);
109 r
= ioctl(sock
, NWIOGUDSSOTYPE
, &uds_sotype
);
110 if (r
!= -1 || errno
!= ENOTTY
)
117 if (uds_sotype
== SOCK_DGRAM
) {
118 return _uds_recvfrom_dgram(sock
, buffer
,
119 length
, flags
, address
, address_len
);
121 return _uds_recvfrom_conn(sock
, buffer
,
122 length
, flags
, address
, address_len
,
127 r
= ioctl(sock
, NWIOGIPOPT
, &ipopt
);
128 if (r
!= -1 || errno
!= ENOTTY
)
132 struct sockaddr_in sin
;
138 rd
= read(sock
, buffer
, length
);
140 if(rd
< 0) return rd
;
142 assert((size_t)rd
>= sizeof(*ip_hdr
));
149 memset(&sin
, 0, sizeof(sin
));
150 sin
.sin_family
= AF_INET
;
151 sin
.sin_addr
.s_addr
= ip_hdr
->ih_src
;
152 sin
.sin_len
= sizeof(sin
);
154 if ((size_t)len
> sizeof(sin
))
155 len
= (int)sizeof(sin
);
156 memcpy(address
, &sin
, len
);
157 *address_len
= sizeof(sin
);
167 static ssize_t
_tcp_recvfrom(int sock
, void *__restrict buffer
, size_t length
,
168 int flags
, struct sockaddr
*__restrict address
,
169 socklen_t
*__restrict address_len
, nwio_tcpconf_t
*tcpconfp
)
173 struct sockaddr_in sin
;
178 fprintf(stderr
, "recvfrom(tcp): flags not implemented\n");
184 r
= read(sock
, buffer
, length
);
186 if (r
>= 0 && address
!= NULL
)
188 sin
.sin_family
= AF_INET
;
189 sin
.sin_addr
.s_addr
= tcpconfp
->nwtc_remaddr
;
190 sin
.sin_port
= tcpconfp
->nwtc_remport
;
191 sin
.sin_len
= sizeof(sin
);
193 if (len
> sizeof(sin
))
195 memcpy(address
, &sin
, len
);
196 *address_len
= sizeof(sin
);
202 static ssize_t
_udp_recvfrom(int sock
, void *__restrict buffer
, size_t length
,
203 int flags
, struct sockaddr
*__restrict address
,
204 socklen_t
*__restrict address_len
, nwio_udpopt_t
*udpoptp
)
209 udp_io_hdr_t
*io_hdrp
;
210 struct sockaddr_in sin
;
215 fprintf(stderr
, "recvfrom(udp): flags not implemented\n");
221 if (udpoptp
->nwuo_flags
& NWUO_RWDATONLY
)
223 if (address
!= NULL
&&
224 (udpoptp
->nwuo_flags
& (NWUO_RA_SET
| NWUO_RP_SET
)) !=
225 (NWUO_RA_SET
| NWUO_RP_SET
))
230 "recvfrom(udp): RWDATONLY on unconnected socket\n");
236 r
= read(sock
, buffer
, length
);
242 sin
.sin_family
= AF_INET
;
243 sin
.sin_addr
.s_addr
= udpoptp
->nwuo_remaddr
;
244 sin
.sin_port
= udpoptp
->nwuo_remport
;
245 sin
.sin_len
= sizeof(sin
);
247 if (len
> sizeof(sin
))
249 memcpy(address
, &sin
, len
);
250 *address_len
= sizeof(sin
);
256 buflen
= sizeof(*io_hdrp
) + length
;
267 r
= read(sock
, buf
, buflen
);
272 fprintf(stderr
, "recvfrom(udp): read failed: %s\n",
274 fprintf(stderr
, "udp opt flags = 0x%x\n", udpoptp
->nwuo_flags
);
281 assert((size_t)r
>= sizeof(*io_hdrp
));
282 length
= r
-sizeof(*io_hdrp
);
285 memcpy(buffer
, &io_hdrp
[1], length
);
289 sin
.sin_family
= AF_INET
;
290 sin
.sin_addr
.s_addr
= io_hdrp
->uih_src_addr
;
291 sin
.sin_port
= io_hdrp
->uih_src_port
;
292 sin
.sin_len
= sizeof(sin
);
294 if (len
> sizeof(sin
))
296 memcpy(address
, &sin
, len
);
297 *address_len
= sizeof(sin
);
303 static ssize_t
_uds_recvfrom_conn(int sock
, void *__restrict buffer
,
304 size_t length
, int flags
, struct sockaddr
*__restrict address
,
305 socklen_t
*__restrict address_len
, struct sockaddr_un
*uds_addr
)
310 /* for connection oriented unix domain sockets (SOCK_STREAM /
317 fprintf(stderr
, "recvfrom(uds): flags not implemented\n");
323 r
= read(sock
, buffer
, length
);
325 if (r
>= 0 && address
!= NULL
)
329 if (len
> sizeof(struct sockaddr_un
))
330 len
= sizeof(struct sockaddr_un
);
331 memcpy(address
, uds_addr
, len
);
332 *address_len
= sizeof(struct sockaddr_un
);
338 static ssize_t
_uds_recvfrom_dgram(int sock
, void *__restrict buffer
,
339 size_t length
, int flags
, struct sockaddr
*__restrict address
,
340 socklen_t
*__restrict address_len
)
345 /* for connectionless unix domain sockets (SOCK_DGRAM) */
350 fprintf(stderr
, "recvfrom(uds): flags not implemented\n");
356 r
= read(sock
, buffer
, length
);
358 if (r
>= 0 && address
!= NULL
)
361 if (len
> sizeof(struct sockaddr_un
))
362 len
= sizeof(struct sockaddr_un
);
363 ioctl(sock
, NWIOGUDSFADDR
, address
);
364 *address_len
= sizeof(struct sockaddr_un
);