1 /* source: xioread.c */
2 /* Copyright Gerhard Rieger 2001-2009 */
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 ((((struct sockaddr_ll
*)&from
.soa
)->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
) {
227 if (pipe
->dtype
& XIOREAD_RECV_SKIPIP
) {
228 /* IP4 raw sockets include the header when passing a packet to the
229 application - we don't need it here. */
230 #if HAVE_STRUCT_IP_IP_HL
231 headlen
= 4*((struct ip
*)buff
)->ip_hl
;
232 #else /* happened on Tru64 */
233 headlen
= 4*((struct ip
*)buff
)->ip_vhl
;
235 if (headlen
> bytes
) {
236 Warn1("xioread(%d, ...)/IP4: short packet", pipe
->fd
);
239 memmove(buff
, ((char *)buff
)+headlen
, bytes
-headlen
);
247 /* does not seem to include header on Linux */
248 /* but sometimes on AIX */
252 /* do nothing, for now */
255 if (pipe
->dtype
& XIOREAD_RECV_ONESHOT
) {
259 Shutdown(pipe
->fd
, SHUT_RD
);
261 if (pipe
->ppid
> 0) {
262 Kill(pipe
->ppid
, SIGUSR1
);
267 if (fromlen
!= pipe
->fd
[0].salen
) {
268 Debug("recvfrom(): wrong peer address length, ignoring packet");
271 if (memcmp(&from
, &pipe
->fd
[0].peersa
.sa
, fromlen
)) {
272 Debug("recvfrom(): other peer address, ignoring packet");
273 Debug16("peer: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
274 pipe
->fd
[0].peersa
.space
[0],
275 pipe
->fd
[0].peersa
.space
[1],
276 pipe
->fd
[0].peersa
.space
[2],
277 pipe
->fd
[0].peersa
.space
[3],
278 pipe
->fd
[0].peersa
.space
[4],
279 pipe
->fd
[0].peersa
.space
[5],
280 pipe
->fd
[0].peersa
.space
[6],
281 pipe
->fd
[0].peersa
.space
[7],
282 pipe
->fd
[0].peersa
.space
[8],
283 pipe
->fd
[0].peersa
.space
[9],
284 pipe
->fd
[0].peersa
.space
[10],
285 pipe
->fd
[0].peersa
.space
[11],
286 pipe
->fd
[0].peersa
.space
[12],
287 pipe
->fd
[0].peersa
.space
[13],
288 pipe
->fd
[0].peersa
.space
[14],
289 pipe
->fd
[0].peersa
.space
[15]);
290 Debug16("from: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
291 from
.space
[0], from
.space
[1],
292 from
.space
[2], from
.space
[3],
293 from
.space
[4], from
.space
[5],
294 from
.space
[6], from
.space
[7],
295 from
.space
[8], from
.space
[9],
296 from
.space
[10], from
.space
[11],
297 from
.space
[12], from
.space
[13],
298 from
.space
[14], from
.space
[15]);
302 #else /* !WITH_RAWIP */
303 Fatal("address requires raw sockets, but they are not compiled in");
305 #endif /* !WITH_RAWIP || WITH_UDP || WITH_UNIX */
307 } else /* ~XIOREAD_RECV_FROM */ {
308 union sockaddr_union from
; socklen_t fromlen
= sizeof(from
);
310 struct msghdr msgh
= {0};
311 char ctrlbuff
[1024]; /* ancillary messages */
313 socket_init(pipe
->para
.socket
.la
.soa
.sa_family
, &from
);
314 /* get source address */
315 msgh
.msg_name
= &from
;
316 msgh
.msg_namelen
= fromlen
;
317 #if HAVE_STRUCT_MSGHDR_MSGCONTROL
318 msgh
.msg_control
= ctrlbuff
;
320 #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
321 msgh
.msg_controllen
= sizeof(ctrlbuff
);
323 if (xiogetpacketsrc(pipe
->fd
, &msgh
) < 0) {
326 xiodopacketinfo(&msgh
, true, false);
327 if (xiocheckpeer(pipe
, &from
, &pipe
->para
.socket
.la
) < 0) {
328 Recvfrom(pipe
->fd
, buff
, bufsiz
, 0, &from
.soa
, &fromlen
); /* drop */
329 errno
= EAGAIN
; return -1;
331 Info1("permitting packet from %s",
332 sockaddr_info((struct sockaddr
*)&from
, fromlen
,
333 infobuff
, sizeof(infobuff
)));
337 Recvfrom(pipe
->fd
, buff
, bufsiz
, 0, &from
.soa
, &fromlen
);
338 } while (bytes
< 0 && errno
== EINTR
);
342 Error6("recvfrom(%d, %p, "F_Zu
", 0, %s, "F_socklen
"): %s",
343 pipe
->fd
, buff
, bufsiz
,
344 sockaddr_info(&from
.soa
, fromlen
, infobuff
, sizeof(infobuff
)),
345 fromlen
, strerror(errno
));
349 Notice2("received packet with "F_Zu
" bytes from %s",
351 sockaddr_info(&from
.soa
, fromlen
, infobuff
, sizeof(infobuff
)));
353 if (!pipe
->para
.socket
.null_eof
) {
354 errno
= EAGAIN
; return -1;
359 switch(from
.soa
.sa_family
) {
363 if (pipe
->dtype
& XIOREAD_RECV_SKIPIP
) {
364 /* IP4 raw sockets include the header when passing a packet to the
365 application - we don't need it here. */
366 #if HAVE_STRUCT_IP_IP_HL
367 headlen
= 4*((struct ip
*)buff
)->ip_hl
;
368 #else /* happened on Tru64 */
369 headlen
= 4*((struct ip
*)buff
)->ip_vhl
;
371 if (headlen
> bytes
) {
372 Warn1("xioread(%d, ...)/IP4: short packet", pipe
->fd
);
375 memmove(buff
, ((char *)buff
)+headlen
, bytes
-headlen
);
382 case AF_INET6
: /* does not seem to include header... */
386 /* do nothing, for now */
392 #endif /* _WITH_SOCKET */
395 Error("internal: undefined read operation");
396 errno
= EINVAL
; return -1;
398 pipe
->actbytes
-= bytes
;
403 /* this function is intended only for some special address types where the
404 select()/poll() calls cannot strictly determine if (more) read data is
405 available. currently this is for the OpenSSL based addresses.
407 ssize_t
xiopending(xiofile_t
*file
) {
410 if (file
->tag
== XIO_TAG_INVALID
) {
411 Error1("xiopending(): invalid xiofile descriptor %p", file
);
416 if (file
->tag
== XIO_TAG_DUAL
) {
417 pipe
= file
->dual
.stream
[0];
418 if (pipe
->tag
== XIO_TAG_INVALID
) {
419 Error1("xiopending(): invalid xiofile sub descriptor %p[0]", file
);
424 pipe
= &file
->stream
;
427 switch (pipe
->dtype
& XIODATA_READMASK
) {
429 case XIOREAD_OPENSSL
:
430 return xiopending_openssl(pipe
);
431 #endif /* WITH_OPENSSL */