1 #include <sys/cdefs.h> 2 #include "namespace.h" 3 4 #include <assert.h> 5 #include <errno.h> 6 #include <stdlib.h> 7 #include <stdio.h> 8 #include <string.h> 9 #include <unistd.h> 10 #include <sys/ioctl.h> 11 #include <sys/socket.h> 12 #include <netinet/in.h> 13 14 #include <net/gen/in.h> 15 #include <net/gen/tcp.h> 16 #include <net/gen/tcp_io.h> 17 #include <net/gen/udp.h> 18 #include <net/gen/udp_hdr.h> 19 #include <net/gen/udp_io.h> 20 21 #include <net/gen/ip_hdr.h> 22 #include <net/gen/icmp_hdr.h> 23 24 #define DEBUG 0 25 26 static ssize_t _tcp_recvfrom(int sock, void *__restrict buffer, size_t length, 27 int flags, struct sockaddr *__restrict address, 28 socklen_t *__restrict address_len, nwio_tcpconf_t *tcpconfp); 29 static ssize_t _udp_recvfrom(int sock, void *__restrict buffer, size_t length, 30 int flags, struct sockaddr *__restrict address, 31 socklen_t *__restrict address_len, nwio_udpopt_t *udpoptp); 32 static ssize_t _uds_recvfrom_conn(int sock, void *__restrict buffer, 33 size_t length, int flags, struct sockaddr *__restrict address, 34 socklen_t *__restrict address_len, struct sockaddr_un *uds_addr); 35 static ssize_t _uds_recvfrom_dgram(int sock, void *__restrict buffer, 36 size_t length, int flags, struct sockaddr *__restrict address, 37 socklen_t *__restrict address_len); 38 39 ssize_t recvfrom(int sock, void *__restrict buffer, size_t length, 40 int flags, struct sockaddr *__restrict address, 41 socklen_t *__restrict address_len) 42 { 43 int r; 44 nwio_tcpconf_t tcpconf; 45 nwio_udpopt_t udpopt; 46 struct sockaddr_un uds_addr; 47 int uds_sotype = -1; 48 49 #if DEBUG 50 fprintf(stderr, "recvfrom: for fd %d\n", sock); 51 #endif 52 53 r= ioctl(sock, NWIOGTCPCONF, &tcpconf); 54 if (r != -1 || errno != ENOTTY) 55 { 56 if (r == -1) 57 return r; 58 return _tcp_recvfrom(sock, buffer, length, flags, 59 address, address_len, &tcpconf); 60 } 61 62 r= ioctl(sock, NWIOGUDPOPT, &udpopt); 63 if (r != -1 || errno != ENOTTY) 64 { 65 if (r == -1) 66 return r; 67 return _udp_recvfrom(sock, buffer, length, flags, 68 address, address_len, &udpopt); 69 } 70 71 r= ioctl(sock, NWIOGUDSSOTYPE, &uds_sotype); 72 if (r != -1 || errno != ENOTTY) 73 { 74 75 if (r == -1) { 76 return r; 77 } 78 79 if (uds_sotype == SOCK_DGRAM) { 80 return _uds_recvfrom_dgram(sock, buffer, 81 length, flags, address, address_len); 82 } else { 83 return _uds_recvfrom_conn(sock, buffer, 84 length, flags, address, address_len, 85 &uds_addr); 86 } 87 } 88 89 { 90 ip_hdr_t *ip_hdr; 91 int ihl, rd; 92 icmp_hdr_t *icmp_hdr; 93 struct sockaddr_in sin; 94 95 rd = read(sock, buffer, length); 96 97 if(rd < 0) return rd; 98 99 assert(rd >= sizeof(*ip_hdr)); 100 101 ip_hdr= buffer; 102 103 if (address != NULL) 104 { 105 int len; 106 memset(&sin, 0, sizeof(sin)); 107 sin.sin_family= AF_INET; 108 sin.sin_addr.s_addr= ip_hdr->ih_src; 109 sin.sin_len= sizeof(sin); 110 len= *address_len; 111 if (len > sizeof(sin)) 112 len= sizeof(sin); 113 memcpy(address, &sin, len); 114 *address_len= sizeof(sin); 115 } 116 117 return rd; 118 } 119 120 #if DEBUG 121 fprintf(stderr, "recvfrom: not implemented for fd %d\n", sock); 122 #endif 123 abort(); 124 } 125 126 static ssize_t _tcp_recvfrom(int sock, void *__restrict buffer, size_t length, 127 int flags, struct sockaddr *__restrict address, 128 socklen_t *__restrict address_len, nwio_tcpconf_t *tcpconfp) 129 { 130 int r; 131 size_t len; 132 struct sockaddr_in sin; 133 134 if (flags != 0) 135 { 136 #if DEBUG 137 fprintf(stderr, "recvfrom(tcp): flags not implemented\n"); 138 #endif 139 errno= ENOSYS; 140 return -1; 141 } 142 143 r = read(sock, buffer, length); 144 145 if (r >= 0 && address != NULL) 146 { 147 sin.sin_family= AF_INET; 148 sin.sin_addr.s_addr= tcpconfp->nwtc_remaddr; 149 sin.sin_port= tcpconfp->nwtc_remport; 150 sin.sin_len= sizeof(sin); 151 len= *address_len; 152 if (len > sizeof(sin)) 153 len= sizeof(sin); 154 memcpy(address, &sin, len); 155 *address_len= sizeof(sin); 156 } 157 158 return r; 159 } 160 161 static ssize_t _udp_recvfrom(int sock, void *__restrict buffer, size_t length, 162 int flags, struct sockaddr *__restrict address, 163 socklen_t *__restrict address_len, nwio_udpopt_t *udpoptp) 164 { 165 int r, t_errno; 166 size_t buflen, len; 167 void *buf; 168 udp_io_hdr_t *io_hdrp; 169 struct sockaddr_in sin; 170 171 if (flags) 172 { 173 #if DEBUG 174 fprintf(stderr, "recvfrom(udp): flags not implemented\n"); 175 #endif 176 errno= ENOSYS; 177 return -1; 178 } 179 180 if (udpoptp->nwuo_flags & NWUO_RWDATONLY) 181 { 182 if (address != NULL && 183 (udpoptp->nwuo_flags & (NWUO_RA_SET | NWUO_RP_SET)) != 184 (NWUO_RA_SET | NWUO_RP_SET)) 185 { 186 187 #if DEBUG 188 fprintf(stderr, 189 "recvfrom(udp): RWDATONLY on unconnected socket\n"); 190 #endif 191 errno= ENOTCONN; 192 return -1; 193 } 194 195 r= read(sock, buffer, length); 196 if (r == -1) 197 return r; 198 199 if (address != NULL) 200 { 201 sin.sin_family= AF_INET; 202 sin.sin_addr.s_addr= udpoptp->nwuo_remaddr; 203 sin.sin_port= udpoptp->nwuo_remport; 204 sin.sin_len= sizeof(sin); 205 len= *address_len; 206 if (len > sizeof(sin)) 207 len= sizeof(sin); 208 memcpy(address, &sin, len); 209 *address_len= sizeof(sin); 210 } 211 212 return r; 213 } 214 215 buflen= sizeof(*io_hdrp) + length; 216 if (buflen < length) 217 { 218 /* Overflow */ 219 errno= EMSGSIZE; 220 return -1; 221 } 222 buf= malloc(buflen); 223 if (buf == NULL) 224 return -1; 225 226 r= read(sock, buf, buflen); 227 if (r == -1) 228 { 229 t_errno= errno; 230 #if DEBUG 231 fprintf(stderr, "recvfrom(udp): read failed: %s\n", 232 strerror(errno)); 233 fprintf(stderr, "udp opt flags = 0x%x\n", udpoptp->nwuo_flags); 234 #endif 235 free(buf); 236 errno= t_errno; 237 return -1; 238 } 239 240 assert(r >= sizeof(*io_hdrp)); 241 length= r-sizeof(*io_hdrp); 242 243 io_hdrp= buf; 244 memcpy(buffer, &io_hdrp[1], length); 245 246 if (address != NULL) 247 { 248 sin.sin_family= AF_INET; 249 sin.sin_addr.s_addr= io_hdrp->uih_src_addr; 250 sin.sin_port= io_hdrp->uih_src_port; 251 sin.sin_len= sizeof(sin); 252 len= *address_len; 253 if (len > sizeof(sin)) 254 len= sizeof(sin); 255 memcpy(address, &sin, len); 256 *address_len= sizeof(sin); 257 } 258 free(buf); 259 return length; 260 } 261 262 static ssize_t _uds_recvfrom_conn(int sock, void *__restrict buffer, 263 size_t length, int flags, struct sockaddr *__restrict address, 264 socklen_t *__restrict address_len, struct sockaddr_un *uds_addr) 265 { 266 int r; 267 size_t len; 268 269 /* for connection oriented unix domain sockets (SOCK_STREAM / 270 * SOCK_SEQPACKET) 271 */ 272 273 if (flags != 0) 274 { 275 #if DEBUG 276 fprintf(stderr, "recvfrom(uds): flags not implemented\n"); 277 #endif 278 errno= ENOSYS; 279 return -1; 280 } 281 282 r = read(sock, buffer, length); 283 284 if (r >= 0 && address != NULL) 285 { 286 287 len= *address_len; 288 if (len > sizeof(struct sockaddr_un)) 289 len= sizeof(struct sockaddr_un); 290 memcpy(address, uds_addr, len); 291 *address_len= sizeof(struct sockaddr_un); 292 } 293 294 return r; 295 } 296 297 static ssize_t _uds_recvfrom_dgram(int sock, void *__restrict buffer, 298 size_t length, int flags, struct sockaddr *__restrict address, 299 socklen_t *__restrict address_len) 300 { 301 int r; 302 size_t len; 303 304 /* for connectionless unix domain sockets (SOCK_DGRAM) */ 305 306 if (flags != 0) 307 { 308 #if DEBUG 309 fprintf(stderr, "recvfrom(uds): flags not implemented\n"); 310 #endif 311 errno= ENOSYS; 312 return -1; 313 } 314 315 r = read(sock, buffer, length); 316 317 if (r >= 0 && address != NULL) 318 { 319 len= *address_len; 320 if (len > sizeof(struct sockaddr_un)) 321 len= sizeof(struct sockaddr_un); 322 ioctl(sock, NWIOGUDSFADDR, address); 323 *address_len= sizeof(struct sockaddr_un); 324 } 325 326 return r; 327 } 328 329