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"
10 #include "xio-termios.h"
11 #include "xio-socket.h"
12 #include "xio-readline.h"
13 #include "xio-openssl.h"
16 /* xioread() performs read() or recvfrom()
17 If result is < 0, errno is valid */
18 ssize_t
xioread(xiofile_t
*file
, void *buff
, size_t bufsiz
) {
26 if (file
->tag
== XIO_TAG_INVALID
) {
27 Error1("xioread(): invalid xiofile descriptor %p", file
);
32 if (file
->tag
== XIO_TAG_DUAL
) {
33 pipe
= file
->dual
.stream
[0];
34 if (pipe
->tag
== XIO_TAG_INVALID
) {
35 Error1("xioread(): invalid xiofile sub descriptor %p[0]", file
);
43 if (pipe
->readbytes
) {
44 if (pipe
->actbytes
== 0) {
45 return 0; /* EOF by count */
48 if (pipe
->actbytes
< bufsiz
) {
49 bufsiz
= pipe
->actbytes
;
53 switch (pipe
->dtype
& XIODATA_READMASK
) {
56 bytes
= Read(pipe
->fd
, buff
, bufsiz
);
57 } while (bytes
< 0 && errno
== EINTR
);
62 case EPIPE
: case ECONNRESET
:
63 Warn4("read(%d, %p, "F_Zu
"): %s",
64 pipe
->fd
, buff
, bufsiz
, strerror(_errno
));
68 Error4("read(%d, %p, "F_Zu
"): %s",
69 pipe
->fd
, buff
, bufsiz
, strerror(_errno
));
78 bytes
= Read(pipe
->fd
, buff
, bufsiz
);
79 } while (bytes
< 0 && errno
== EINTR
);
83 Notice4("read(%d, %p, "F_Zu
"): %s (probably PTY closed)",
84 pipe
->fd
, buff
, bufsiz
, strerror(_errno
));
87 Error4("read(%d, %p, "F_Zu
"): %s",
88 pipe
->fd
, buff
, bufsiz
, strerror(_errno
));
96 case XIOREAD_READLINE
:
97 if ((bytes
= xioread_readline(pipe
, buff
, bufsiz
)) < 0) {
101 #endif /* WITH_READLINE */
104 case XIOREAD_OPENSSL
:
105 /* this function prints its error messages */
106 if ((bytes
= xioread_openssl(pipe
, buff
, bufsiz
)) < 0) {
110 #endif /* WITH_OPENSSL */
114 if (pipe
->dtype
& XIOREAD_RECV_FROM
) {
115 #if WITH_RAWIP || WITH_UDP || WITH_UNIX
116 struct msghdr msgh
= {0};
117 union sockaddr_union from
= {{0}};
118 socklen_t fromlen
= sizeof(from
);
120 char ctrlbuff
[1024]; /* ancillary messages */
122 msgh
.msg_name
= &from
;
123 msgh
.msg_namelen
= fromlen
;
124 #if HAVE_STRUCT_MSGHDR_MSGCONTROL
125 msgh
.msg_control
= ctrlbuff
;
127 #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
128 msgh
.msg_controllen
= sizeof(ctrlbuff
);
130 if (xiogetpacketsrc(pipe
->fd
, &msgh
) < 0) {
135 Recvfrom(pipe
->fd
, buff
, bufsiz
, 0, &from
.soa
, &fromlen
);
136 } while (bytes
< 0 && errno
== EINTR
);
140 Error6("recvfrom(%d, %p, "F_Zu
", 0, %s, {"F_socklen
"}): %s",
141 pipe
->fd
, buff
, bufsiz
,
142 sockaddr_info(&from
.soa
, fromlen
, infobuff
, sizeof(infobuff
)),
143 fromlen
, strerror(errno
));
147 /* on packet type we also receive outgoing packets, this is not desired
149 #if defined(PF_PACKET) && defined(PACKET_OUTGOING)
150 if (from
.soa
.sa_family
== PF_PACKET
) {
151 if ((from
.ll
.sll_pkttype
& PACKET_OUTGOING
)
153 errno
= EAGAIN
; return -1;
156 #endif /* defined(PF_PACKET) && defined(PACKET_OUTGOING) */
158 Notice2("received packet with "F_Zu
" bytes from %s",
160 sockaddr_info(&from
.soa
, fromlen
, infobuff
, sizeof(infobuff
)));
162 if (!pipe
->para
.socket
.null_eof
) {
163 errno
= EAGAIN
; return -1;
168 if (pipe
->peersa
.soa
.sa_family
!= PF_UNSPEC
) {
169 /* a peer address is registered, so we need to check if it matches */
170 #if 0 /* with UNIX sockets we find inconsistent lengths */
171 if (fromlen
!= pipe
->salen
) {
172 Info("recvfrom(): wrong peer address length, ignoring packet");
173 errno
= EAGAIN
; return -1;
176 if (pipe
->dtype
& XIOREAD_RECV_SKIPIP
) {
177 if (pipe
->peersa
.soa
.sa_family
!= from
.soa
.sa_family
) {
178 Info("recvfrom(): wrong peer protocol, ignoring packet");
179 errno
= EAGAIN
; return -1;
182 switch (pipe
->peersa
.soa
.sa_family
) {
184 if (pipe
->peersa
.ip4
.sin_addr
.s_addr
!=
185 from
.ip4
.sin_addr
.s_addr
) {
186 Info("recvfrom(): wrong peer address, ignoring packet");
187 errno
= EAGAIN
; return -1;
191 #endif /* WITH_IP4 */
193 switch (pipe
->peersa
.soa
.sa_family
) {
196 if (strncmp(pipe
->peersa
.un
.sun_path
, from
.un
.sun_path
,
197 sizeof(from
.un
.sun_path
))) {
198 Info("recvfrom(): wrong peer address, ignoring packet");
199 errno
= EAGAIN
; return -1;
205 /* e.g. Solaris recvfrom sets a __sin6_src_id component */
206 if (memcmp(&from
.ip6
.sin6_addr
, &pipe
->peersa
.ip6
.sin6_addr
,
207 sizeof(from
.ip6
.sin6_addr
)) ||
208 from
.ip6
.sin6_port
!= pipe
->peersa
.ip6
.sin6_port
) {
209 Info("recvfrom(): wrong peer address, ignoring packet");
210 errno
= EAGAIN
; return -1;
213 #endif /* WITH_IP6 */
215 if (memcmp(&from
, &pipe
->peersa
, fromlen
)) {
216 Info("recvfrom(): wrong peer address, ignoring packet");
217 errno
= EAGAIN
; return -1;
223 switch(from
.soa
.sa_family
) {
226 #endif /* HAVE_STRUCT_IP */
230 if (pipe
->dtype
& XIOREAD_RECV_SKIPIP
) {
231 /* IP4 raw sockets include the header when passing a packet to the
232 application - we don't need it here. */
233 #if HAVE_STRUCT_IP_IP_HL
234 headlen
= 4*((struct ip
*)buff
)->ip_hl
;
235 #else /* happened on Tru64 */
236 headlen
= 4*((struct ip
*)buff
)->ip_vhl
;
238 if (headlen
> bytes
) {
239 Warn1("xioread(%d, ...)/IP4: short packet", pipe
->fd
);
242 memmove(buff
, ((char *)buff
)+headlen
, bytes
-headlen
);
246 #endif /* HAVE_STRUCT_IP */
251 /* does not seem to include header on Linux */
252 /* but sometimes on AIX */
256 /* do nothing, for now */
259 if (pipe
->dtype
& XIOREAD_RECV_ONESHOT
) {
263 Shutdown(pipe
->fd
, SHUT_RD
);
265 if (pipe
->ppid
> 0) {
266 Kill(pipe
->ppid
, SIGUSR1
);
271 if (fromlen
!= pipe
->fd
[0].salen
) {
272 Debug("recvfrom(): wrong peer address length, ignoring packet");
275 if (memcmp(&from
, &pipe
->fd
[0].peersa
.sa
, fromlen
)) {
276 Debug("recvfrom(): other peer address, ignoring packet");
277 Debug16("peer: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
278 pipe
->fd
[0].peersa
.space
[0],
279 pipe
->fd
[0].peersa
.space
[1],
280 pipe
->fd
[0].peersa
.space
[2],
281 pipe
->fd
[0].peersa
.space
[3],
282 pipe
->fd
[0].peersa
.space
[4],
283 pipe
->fd
[0].peersa
.space
[5],
284 pipe
->fd
[0].peersa
.space
[6],
285 pipe
->fd
[0].peersa
.space
[7],
286 pipe
->fd
[0].peersa
.space
[8],
287 pipe
->fd
[0].peersa
.space
[9],
288 pipe
->fd
[0].peersa
.space
[10],
289 pipe
->fd
[0].peersa
.space
[11],
290 pipe
->fd
[0].peersa
.space
[12],
291 pipe
->fd
[0].peersa
.space
[13],
292 pipe
->fd
[0].peersa
.space
[14],
293 pipe
->fd
[0].peersa
.space
[15]);
294 Debug16("from: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
295 from
.space
[0], from
.space
[1],
296 from
.space
[2], from
.space
[3],
297 from
.space
[4], from
.space
[5],
298 from
.space
[6], from
.space
[7],
299 from
.space
[8], from
.space
[9],
300 from
.space
[10], from
.space
[11],
301 from
.space
[12], from
.space
[13],
302 from
.space
[14], from
.space
[15]);
306 #else /* !WITH_RAWIP */
307 Fatal("address requires raw sockets, but they are not compiled in");
309 #endif /* !WITH_RAWIP || WITH_UDP || WITH_UNIX */
311 } else /* ~XIOREAD_RECV_FROM */ {
312 union sockaddr_union from
; socklen_t fromlen
= sizeof(from
);
314 struct msghdr msgh
= {0};
315 char ctrlbuff
[1024]; /* ancillary messages */
317 socket_init(pipe
->para
.socket
.la
.soa
.sa_family
, &from
);
318 /* get source address */
319 msgh
.msg_name
= &from
;
320 msgh
.msg_namelen
= fromlen
;
321 #if HAVE_STRUCT_MSGHDR_MSGCONTROL
322 msgh
.msg_control
= ctrlbuff
;
324 #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
325 msgh
.msg_controllen
= sizeof(ctrlbuff
);
327 if (xiogetpacketsrc(pipe
->fd
, &msgh
) < 0) {
330 xiodopacketinfo(&msgh
, true, false);
331 if (xiocheckpeer(pipe
, &from
, &pipe
->para
.socket
.la
) < 0) {
332 Recvfrom(pipe
->fd
, buff
, bufsiz
, 0, &from
.soa
, &fromlen
); /* drop */
333 errno
= EAGAIN
; return -1;
335 Info1("permitting packet from %s",
336 sockaddr_info((struct sockaddr
*)&from
, fromlen
,
337 infobuff
, sizeof(infobuff
)));
341 Recvfrom(pipe
->fd
, buff
, bufsiz
, 0, &from
.soa
, &fromlen
);
342 } while (bytes
< 0 && errno
== EINTR
);
346 Error6("recvfrom(%d, %p, "F_Zu
", 0, %s, "F_socklen
"): %s",
347 pipe
->fd
, buff
, bufsiz
,
348 sockaddr_info(&from
.soa
, fromlen
, infobuff
, sizeof(infobuff
)),
349 fromlen
, strerror(errno
));
353 Notice2("received packet with "F_Zu
" bytes from %s",
355 sockaddr_info(&from
.soa
, fromlen
, infobuff
, sizeof(infobuff
)));
357 if (!pipe
->para
.socket
.null_eof
) {
358 errno
= EAGAIN
; return -1;
363 switch(from
.soa
.sa_family
) {
366 #endif /* HAVE_STRUCT_IP */
370 if (pipe
->dtype
& XIOREAD_RECV_SKIPIP
) {
371 /* IP4 raw sockets include the header when passing a packet to the
372 application - we don't need it here. */
373 #if HAVE_STRUCT_IP_IP_HL
374 headlen
= 4*((struct ip
*)buff
)->ip_hl
;
375 #else /* happened on Tru64 */
376 headlen
= 4*((struct ip
*)buff
)->ip_vhl
;
378 if (headlen
> bytes
) {
379 Warn1("xioread(%d, ...)/IP4: short packet", pipe
->fd
);
382 memmove(buff
, ((char *)buff
)+headlen
, bytes
-headlen
);
386 #endif /* HAVE_STRUCT_IP */
390 case AF_INET6
: /* does not seem to include header... */
394 /* do nothing, for now */
400 #endif /* _WITH_SOCKET */
403 Error("internal: undefined read operation");
404 errno
= EINVAL
; return -1;
406 pipe
->actbytes
-= bytes
;
411 /* this function is intended only for some special address types where the
412 select()/poll() calls cannot strictly determine if (more) read data is
413 available. currently this is for the OpenSSL based addresses.
415 ssize_t
xiopending(xiofile_t
*file
) {
418 if (file
->tag
== XIO_TAG_INVALID
) {
419 Error1("xiopending(): invalid xiofile descriptor %p", file
);
424 if (file
->tag
== XIO_TAG_DUAL
) {
425 pipe
= file
->dual
.stream
[0];
426 if (pipe
->tag
== XIO_TAG_INVALID
) {
427 Error1("xiopending(): invalid xiofile sub descriptor %p[0]", file
);
432 pipe
= &file
->stream
;
435 switch (pipe
->dtype
& XIODATA_READMASK
) {
437 case XIOREAD_OPENSSL
:
438 return xiopending_openssl(pipe
);
439 #endif /* WITH_OPENSSL */