Version 1.8.0.0
[socat.git] / xioread.c
blobb4bb530195f005f22ea420da8e87c330eeea339b
1 /* source: xioread.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* this is the source of the extended read function */
7 #include "xiosysincludes.h"
8 #include "xioopen.h"
10 #include "xio-termios.h"
11 #include "xio-socket.h"
12 #include "xio-posixmq.h"
13 #include "xio-readline.h"
14 #include "xio-openssl.h"
17 /* xioread() performs read() or recvfrom()
18 If result is < 0, errno is valid */
19 ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
20 ssize_t bytes;
21 #if WITH_IP6 && 0
22 int nexthead;
23 #endif
24 struct single *pipe;
25 int _errno;
27 if (file->tag == XIO_TAG_INVALID || file->tag & XIO_TAG_CLOSED) {
28 Error1("xioread(): invalid xiofile descriptor %p", file);
29 errno = EINVAL;
30 return -1;
33 if (file->tag == XIO_TAG_DUAL) {
34 pipe = file->dual.stream[0];
35 if (pipe->tag == XIO_TAG_INVALID || file->tag & XIO_TAG_CLOSED) {
36 Error1("xioread(): invalid xiofile sub descriptor %p[0]", file);
37 errno = EINVAL;
38 return -1;
40 } else {
41 pipe = &file->stream;
44 if (pipe->readbytes) {
45 if (pipe->actbytes == 0) {
46 Info1("xioread(%d, ...): readbytes consumed, inserting EOF", pipe->fd);
47 return 0; /* EOF by count */
50 if (pipe->actbytes < bufsiz) {
51 bufsiz = pipe->actbytes;
55 switch (pipe->dtype & XIODATA_READMASK) {
56 case XIOREAD_STREAM:
57 do {
58 bytes = Read(pipe->fd, buff, bufsiz);
59 } while (bytes < 0 && errno == EINTR);
60 if (bytes < 0) {
61 _errno = errno;
62 switch (_errno) {
63 case EPIPE:
64 case ECONNRESET:
65 /*PASSTHROUGH*/
66 default:
67 Error4("read(%d, %p, "F_Zu"): %s",
68 pipe->fd, buff, bufsiz, strerror(_errno));
70 errno = _errno;
71 return -1;
73 break;
75 case XIOREAD_PTY:
77 int eio = 0;
78 bool m = false; /* loop message printed? */
79 while (true) {
80 do {
81 bytes = Read(pipe->fd, buff, bufsiz);
82 } while (bytes < 0 && errno == EINTR);
83 if (bytes < 0) {
84 _errno = errno;
85 if (_errno != EIO) {
86 Error4("read(%d, %p, "F_Zu"): %s", pipe->fd, buff, bufsiz, strerror(_errno));
87 errno = _errno;
88 return -1;
90 if (pipe->para.exec.sitout_eio.tv_sec == 0 &&
91 pipe->para.exec.sitout_eio.tv_usec == 0) {
92 Notice4("read(%d, %p, "F_Zu"): %s (probably PTY closed)",
93 pipe->fd, buff, bufsiz, strerror(_errno));
94 return 0;
96 if (!m) {
97 /* Starting first iteration: calc and report */
98 /* Round up to 10ms */
99 eio = 100*pipe->para.exec.sitout_eio.tv_sec +
100 (pipe->para.exec.sitout_eio.tv_usec+9999)/10000;
101 Notice3("xioread(fd=%d): EIO, sitting out %u.%02lus for recovery", pipe->fd, eio/100, (unsigned long)eio%100);
102 m = true;
104 poll(NULL, 0, 10);
105 if (--eio <= 0) {
106 /* Timeout */
107 Error4("read(%d, %p, "F_Zu"): %s", pipe->fd, buff, bufsiz, strerror(_errno));
108 errno = _errno;
109 return -1;
111 /* Not reached */
112 } else
113 break; /* no error */
116 return bytes;
117 break;
119 #if WITH_POSIXMQ
120 case XIOREAD_POSIXMQ:
121 if ((bytes = xioread_posixmq(pipe, buff, bufsiz)) < 0) {
122 return -1;
124 if (pipe->dtype & XIOREAD_RECV_ONESHOT) {
125 pipe->eof = 2;
127 break;
128 #endif /* WITH_POSIXMQ */
130 #if WITH_READLINE
131 case XIOREAD_READLINE:
132 if ((bytes = xioread_readline(pipe, buff, bufsiz)) < 0) {
133 return -1;
135 break;
136 #endif /* WITH_READLINE */
138 #if WITH_OPENSSL
139 case XIOREAD_OPENSSL:
140 /* this function prints its error messages */
141 if ((bytes = xioread_openssl(pipe, buff, bufsiz)) < 0) {
142 return -1;
144 break;
145 #endif /* WITH_OPENSSL */
147 #if _WITH_SOCKET
148 case XIOREAD_RECV:
149 if (pipe->dtype & XIOREAD_RECV_NOCHECK) {
150 /* No need to check peer address */
151 do {
152 bytes =
153 Recv(pipe->fd, buff, bufsiz, 0);
154 } while (bytes < 0 && errno == EINTR);
155 if (bytes < 0) {
156 _errno = errno;
157 Error3("recvfrom(%d, %p, "F_Zu", 0", pipe->fd, buff, bufsiz);
158 errno = _errno;
159 return -1;
161 Notice1("received packet with "F_Zu" bytes", bytes);
162 if (bytes == 0) {
163 if (!pipe->para.socket.null_eof) {
164 errno = EAGAIN; return -1;
166 return bytes;
169 } else if (pipe->dtype & XIOREAD_RECV_FROM) {
170 /* Receiving packets in addresses of RECVFROM types, the sender address
171 has already been determined in OPEN phase. */
172 Debug1("%s(): XIOREAD_RECV and XIOREAD_RECV_FROM (peer checks already done)",
173 __func__);
174 #if WITH_RAWIP || WITH_UDP || WITH_UNIX
175 struct msghdr msgh = {0};
176 union sockaddr_union from = {{0}};
177 socklen_t fromlen = sizeof(from);
178 char infobuff[256];
179 char ctrlbuff[1024]; /* ancillary messages */
180 int rc;
182 msgh.msg_name = &from;
183 msgh.msg_namelen = fromlen;
184 #if HAVE_STRUCT_MSGHDR_MSGCONTROL
185 msgh.msg_control = ctrlbuff;
186 #endif
187 #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
188 msgh.msg_controllen = sizeof(ctrlbuff);
189 #endif
190 while ((rc = xiogetancillary(pipe->fd, &msgh,
191 MSG_PEEK
192 #ifdef MSG_TRUNC
193 |MSG_TRUNC
194 #endif
195 )) < 0 &&
196 errno == EINTR) ;
197 if (rc < 0) return -1;
199 /* Note: we do not call xiodopacketinfo() and xiocheckpeer() here because
200 that already happened in xioopen() / _xioopen_dgram_recvfrom() ... */
202 do {
203 bytes =
204 Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen);
205 } while (bytes < 0 && errno == EINTR);
206 if (bytes < 0) {
207 char infobuff[256];
208 _errno = errno;
209 Error6("recvfrom(%d, %p, "F_Zu", 0, %s, {"F_socklen"}): %s",
210 pipe->fd, buff, bufsiz,
211 sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)),
212 fromlen, strerror(errno));
213 errno = _errno;
214 return -1;
217 #if defined(PF_PACKET) && !defined(PACKET_IGNORE_OUTGOING) && defined(PACKET_OUTGOING)
218 /* In future versions there may be an option that controls receiving of
219 outgoing packets, but currently it is hardcoded that we try to avoid
220 them - either by once setting socket option PACKET_IGNORE_OUTGOING
221 when available, otherwise by checking flag PACKET_OUTGOING per packet.
223 if (from.soa.sa_family == PF_PACKET) {
224 if ((from.ll.sll_pkttype & PACKET_OUTGOING) != 0) {
225 Info2("%s(fd=%d): ignoring outgoing packet", __func__, pipe->fd);
226 errno = EAGAIN;
227 return -1;
229 Debug2("%s(fd=%d): packet is not outgoing - process it", __func__, pipe->fd);
231 #endif /* defined(PF_PACKET) && !defined(PACKET_IGNORE_OUTGOING) && defined(PACKET_OUTGOING) */
233 #if defined(PF_PACKET) && HAVE_STRUCT_TPACKET_AUXDATA
234 if (from.soa.sa_family == PF_PACKET) {
235 Debug3("xioread(FD=%d, ...): auxdata: flag=%d, vlan-id=%d",
236 pipe->fd, pipe->para.socket.ancill_flag.packet_auxdata,
237 pipe->para.socket.ancill_data_packet_auxdata.tp_vlan_tci);
238 if (pipe->para.socket.retrieve_vlan &&
239 pipe->para.socket.ancill_flag.packet_auxdata &&
240 pipe->para.socket.ancill_data_packet_auxdata.tp_vlan_tci != 0) {
241 int offs = 12; /* packet type id in Ethernet header */
242 Debug1("xioread(%d, ...): restoring VLAN id from auxdata->tp_vlan_tci",
243 pipe->fd);
244 if (bytes+4 > bufsiz) {
245 Error("buffer too small to restore VLAN id");
247 memmove((char *)buff+offs+4, (char *)buff+offs, bytes-offs);
248 ((unsigned short *)((char *)buff+offs))[0] = htons(ETH_P_8021Q);
249 ((unsigned short *)((char *)buff+offs))[1] =
250 htons(pipe->para.socket.ancill_data_packet_auxdata.tp_vlan_tci);
251 bytes += 4;
254 #endif /* defined(PF_PACKET && HAVE_STRUCT_TPACKET_AUXDATA */
256 Notice2("received packet with "F_Zu" bytes from %s",
257 bytes,
258 sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)));
259 if (bytes == 0) {
260 if (!pipe->para.socket.null_eof) {
261 errno = EAGAIN; return -1;
263 return bytes;
266 if (pipe->peersa.soa.sa_family != PF_UNSPEC) {
267 /* a peer address is registered, so we need to check if it matches */
268 #if 0 /* with UNIX sockets we find inconsistent lengths */
269 if (fromlen != pipe->salen) {
270 Info("recvfrom(): wrong peer address length, ignoring packet");
271 errno = EAGAIN; return -1;
273 #endif
274 if (pipe->dtype & XIOREAD_RECV_SKIPIP) {
275 if (pipe->peersa.soa.sa_family != from.soa.sa_family) {
276 Info("recvfrom(): wrong peer protocol, ignoring packet");
277 errno = EAGAIN; return -1;
279 #if WITH_IP4
280 switch (pipe->peersa.soa.sa_family) {
281 case PF_INET:
282 if (pipe->peersa.ip4.sin_addr.s_addr !=
283 from.ip4.sin_addr.s_addr) {
284 Info("recvfrom(): wrong peer address, ignoring packet");
285 errno = EAGAIN; return -1;
287 break;
289 #endif /* WITH_IP4 */
290 } else {
291 switch (pipe->peersa.soa.sa_family) {
292 #if 0
293 case PF_UNIX:
294 if (strncmp(pipe->peersa.un.sun_path, from.un.sun_path,
295 sizeof(from.un.sun_path))) {
296 Info("recvfrom(): wrong peer address, ignoring packet");
297 errno = EAGAIN; return -1;
299 break;
300 #endif
301 #if WITH_IP6
302 case PF_INET6:
303 /* e.g. Solaris recvfrom sets a __sin6_src_id component */
304 if (memcmp(&from.ip6.sin6_addr, &pipe->peersa.ip6.sin6_addr,
305 sizeof(from.ip6.sin6_addr)) ||
306 from.ip6.sin6_port != pipe->peersa.ip6.sin6_port) {
307 Info("recvfrom(): wrong peer address, ignoring packet");
308 errno = EAGAIN; return -1;
310 break;
311 #endif /* WITH_IP6 */
312 default:
313 if (memcmp(&from, &pipe->peersa, fromlen)) {
314 Info("recvfrom(): wrong peer address, ignoring packet");
315 errno = EAGAIN; return -1;
321 switch(from.soa.sa_family) {
322 #if HAVE_STRUCT_IP
323 int headlen;
324 #endif /* HAVE_STRUCT_IP */
325 #if WITH_IP4
326 case AF_INET:
327 #if HAVE_STRUCT_IP
328 if (pipe->dtype & XIOREAD_RECV_SKIPIP) {
329 /* IP4 raw sockets include the header when passing a packet to the
330 application - we don't need it here. */
331 #if HAVE_STRUCT_IP_IP_HL
332 headlen = 4*((struct ip *)buff)->ip_hl;
333 #else /* happened on Tru64 */
334 headlen = 4*((struct ip *)buff)->ip_vhl;
335 #endif
336 if (headlen > bytes) {
337 Warn1("xioread(%d, ...)/IP4: short packet", pipe->fd);
338 bytes = 0;
339 } else {
340 memmove(buff, ((char *)buff)+headlen, bytes-headlen);
341 bytes -= headlen;
344 #endif /* HAVE_STRUCT_IP */
345 break;
346 #endif
347 #if WITH_IP6
348 case AF_INET6:
349 /* does not seem to include header on Linux */
350 /* but sometimes on AIX */
351 break;
352 #endif
353 default:
354 /* do nothing, for now */
355 break;
357 if (pipe->dtype & XIOREAD_RECV_ONESHOT) {
358 #if 1
359 pipe->eof = 2;
360 #else
361 Shutdown(pipe->fd, SHUT_RD);
362 #endif
363 if (pipe->triggerfd >= 0) {
364 Info("notifying parent that socket is ready again");
365 Close(pipe->triggerfd);
366 pipe->triggerfd = -1;
370 #if 0
371 if (fromlen != pipe->fd[0].salen) {
372 Debug("recvfrom(): wrong peer address length, ignoring packet");
373 continue;
375 if (memcmp(&from, &pipe->fd[0].peersa.sa, fromlen)) {
376 Debug("recvfrom(): other peer address, ignoring packet");
377 Debug16("peer: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
378 pipe->fd[0].peersa.space[0],
379 pipe->fd[0].peersa.space[1],
380 pipe->fd[0].peersa.space[2],
381 pipe->fd[0].peersa.space[3],
382 pipe->fd[0].peersa.space[4],
383 pipe->fd[0].peersa.space[5],
384 pipe->fd[0].peersa.space[6],
385 pipe->fd[0].peersa.space[7],
386 pipe->fd[0].peersa.space[8],
387 pipe->fd[0].peersa.space[9],
388 pipe->fd[0].peersa.space[10],
389 pipe->fd[0].peersa.space[11],
390 pipe->fd[0].peersa.space[12],
391 pipe->fd[0].peersa.space[13],
392 pipe->fd[0].peersa.space[14],
393 pipe->fd[0].peersa.space[15]);
394 Debug16("from: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
395 from.space[0], from.space[1],
396 from.space[2], from.space[3],
397 from.space[4], from.space[5],
398 from.space[6], from.space[7],
399 from.space[8], from.space[9],
400 from.space[10], from.space[11],
401 from.space[12], from.space[13],
402 from.space[14], from.space[15]);
403 continue;
405 #endif
406 #else /* !(WITH_RAWIP || WITH_UDP || WITH_UNIX) */
407 Fatal("address requires raw sockets, but they are not compiled in");
408 return -1;
409 #endif /* !(WITH_RAWIP || WITH_UDP || WITH_UNIX) */
411 } else /* ~(XIOREAD_RECV_FROM|XIOREAD_RECV_FROM) */ {
412 /* Receiving packets without planning to answer to the sender, but we
413 might need sender info for some checks, thus we use recvfrom() */
414 struct msghdr msgh = {0};
415 union sockaddr_union from = {{ 0 }};
416 socklen_t fromlen = sizeof(from);
417 char infobuff[256];
418 char ctrlbuff[1024]; /* ancillary messages */
419 int rc;
421 Debug1("%s(): XIOREAD_RECV and not XIOREAD_RECV_FROM (peer checks to be done)",
422 __func__);
424 /* get source address */
425 msgh.msg_name = &from;
426 msgh.msg_namelen = fromlen;
427 #if HAVE_STRUCT_MSGHDR_MSGCONTROL
428 msgh.msg_control = ctrlbuff;
429 #endif
430 #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
431 msgh.msg_controllen = sizeof(ctrlbuff);
432 #endif
433 while ((rc = xiogetancillary(pipe->fd, &msgh,
434 MSG_PEEK
435 #ifdef MSG_TRUNC
436 |MSG_TRUNC
437 #endif
438 )) < 0 &&
439 errno == EINTR) ;
440 if (rc < 0) return -1;
442 xiodopacketinfo(pipe, &msgh, true, false);
443 if (xiocheckpeer(pipe, &from, &pipe->para.socket.la) < 0) {
444 Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen); /* drop */
445 errno = EAGAIN; return -1;
447 Info1("permitting packet from %s",
448 sockaddr_info((struct sockaddr *)&from, fromlen,
449 infobuff, sizeof(infobuff)));
451 do {
452 bytes =
453 Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen);
454 } while (bytes < 0 && errno == EINTR);
455 if (bytes < 0) {
456 char infobuff[256];
457 _errno = errno;
458 Error6("recvfrom(%d, %p, "F_Zu", 0, %s, "F_socklen"): %s",
459 pipe->fd, buff, bufsiz,
460 sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)),
461 fromlen, strerror(errno));
462 errno = _errno;
463 return -1;
466 #if defined(PF_PACKET) && !defined(PACKET_IGNORE_OUTGOING) && defined(PACKET_OUTGOING)
467 /* For remarks see similar section above */
468 if (from.soa.sa_family == PF_PACKET) {
469 if ((from.ll.sll_pkttype & PACKET_OUTGOING) != 0) {
470 Info2("%s(fd=%d): ignoring outgoing packet", __func__, pipe->fd);
471 errno = EAGAIN;
472 return -1;
474 Debug2("%s(fd=%d): packet is not outgoing - process it", __func__, pipe->fd);
476 #endif /* defined(PF_PACKET) && !defined(PACKET_IGNORE_OUTGOING) && defined(PACKET_OUTGOING) */
478 #if defined(PF_PACKET) && HAVE_STRUCT_TPACKET_AUXDATA
479 if (from.soa.sa_family == PF_PACKET) {
480 Debug3("xioread(%d, ...): auxdata: flag=%d, vlan-id=%d",
481 pipe->fd, pipe->para.socket.ancill_flag.packet_auxdata,
482 pipe->para.socket.ancill_data_packet_auxdata.tp_vlan_tci);
483 if (pipe->para.socket.ancill_flag.packet_auxdata &&
484 pipe->para.socket.ancill_data_packet_auxdata.tp_vlan_tci &&
485 pipe->para.socket.ancill_data_packet_auxdata.tp_net >= 2) {
486 Debug2("xioread(%d, ...): restoring VLAN id %d", pipe->fd, pipe->para.socket.ancill_data_packet_auxdata.tp_vlan_tci);
487 int offs = pipe->para.socket.ancill_data_packet_auxdata.tp_net - 2;
488 if (bytes+4 > bufsiz) {
489 Error("buffer too small to restore VLAN id");
491 Debug3("xioread(): memmove(%p, %p, "F_Zu")", (char *)buff+offs+4, (char *)buff+offs, bytes-offs);
492 memmove((char *)buff+offs+4, (char *)buff+offs, bytes-offs);
493 ((unsigned short *)((char *)buff+offs))[0] = htons(ETH_P_8021Q);
494 ((unsigned short *)((char *)buff+offs))[1] =
495 htons(pipe->para.socket.ancill_data_packet_auxdata.tp_vlan_tci);
496 bytes += 4;
499 #endif /* defined(PF_PACKET) &&& HAVE_STRUCT_TPACKET_AUXDATA */
501 Notice2("received packet with "F_Zu" bytes from %s",
502 bytes,
503 sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)));
505 if (bytes == 0) {
506 if (!pipe->para.socket.null_eof) {
507 errno = EAGAIN; return -1;
509 return bytes;
512 switch(from.soa.sa_family) {
513 #if HAVE_STRUCT_IP
514 int headlen;
515 #endif /* HAVE_STRUCT_IP */
516 #if WITH_IP4
517 case AF_INET:
518 #if HAVE_STRUCT_IP
519 if (pipe->dtype & XIOREAD_RECV_SKIPIP) {
520 /* IP4 raw sockets include the header when passing a packet to the
521 application - we don't need it here. */
522 #if HAVE_STRUCT_IP_IP_HL
523 headlen = 4*((struct ip *)buff)->ip_hl;
524 #else /* happened on Tru64 */
525 headlen = 4*((struct ip *)buff)->ip_vhl;
526 #endif
527 if (headlen > bytes) {
528 Warn1("xioread(%d, ...)/IP4: short packet", pipe->fd);
529 bytes = 0;
530 } else {
531 memmove(buff, ((char *)buff)+headlen, bytes-headlen);
532 bytes -= headlen;
535 #endif /* HAVE_STRUCT_IP */
536 break;
537 #endif
538 #if WITH_IP6
539 case AF_INET6: /* does not seem to include header... */
540 break;
541 #endif
542 default:
543 /* do nothing, for now */
544 break;
548 break;
549 #endif /* _WITH_SOCKET */
551 default:
552 Error("internal: undefined read operation");
553 errno = EINVAL; return -1;
555 pipe->actbytes -= bytes;
556 return bytes;
560 /* this function is intended only for some special address types where the
561 select()/poll() calls cannot strictly determine if (more) read data is
562 available. currently this is for the OpenSSL based addresses.
564 ssize_t xiopending(xiofile_t *file) {
565 struct single *pipe;
567 if (file->tag == XIO_TAG_INVALID || file->tag & XIO_TAG_CLOSED) {
568 Error1("xiopending(): invalid xiofile descriptor %p", file);
569 errno = EINVAL;
570 return -1;
573 if (file->tag == XIO_TAG_DUAL) {
574 pipe = file->dual.stream[0];
575 if (pipe->tag == XIO_TAG_INVALID || file->tag & XIO_TAG_CLOSED) {
576 Error1("xiopending(): invalid xiofile sub descriptor %p[0]", file);
577 errno = EINVAL;
578 return -1;
580 } else {
581 pipe = &file->stream;
584 switch (pipe->dtype & XIODATA_READMASK) {
585 #if WITH_OPENSSL
586 case XIOREAD_OPENSSL:
587 return xiopending_openssl(pipe);
588 #endif /* WITH_OPENSSL */
589 default:
590 return 0;