add listen-timeout to function as an accept timeout
[socat/sam.git] / xioread.c
blob04db1ebb47741ba8b174d77e478f9591c1c6ae06
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"
8 #include "xioopen.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) {
19 ssize_t bytes;
20 #if WITH_IP6 && 0
21 int nexthead;
22 #endif
23 struct single *pipe;
24 int _errno;
26 if (file->tag == XIO_TAG_INVALID) {
27 Error1("xioread(): invalid xiofile descriptor %p", file);
28 errno = EINVAL;
29 return -1;
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);
36 errno = EINVAL;
37 return -1;
39 } else {
40 pipe = &file->stream;
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) {
54 case XIOREAD_STREAM:
55 do {
56 bytes = Read(pipe->fd, buff, bufsiz);
57 } while (bytes < 0 && errno == EINTR);
58 if (bytes < 0) {
59 _errno = errno;
60 switch (_errno) {
61 #if 1
62 case EPIPE: case ECONNRESET:
63 Warn4("read(%d, %p, "F_Zu"): %s",
64 pipe->fd, buff, bufsiz, strerror(_errno));
65 break;
66 #endif
67 default:
68 Error4("read(%d, %p, "F_Zu"): %s",
69 pipe->fd, buff, bufsiz, strerror(_errno));
71 errno = _errno;
72 return -1;
74 break;
76 case XIOREAD_PTY:
77 do {
78 bytes = Read(pipe->fd, buff, bufsiz);
79 } while (bytes < 0 && errno == EINTR);
80 if (bytes < 0) {
81 _errno = errno;
82 if (_errno == EIO) {
83 Notice4("read(%d, %p, "F_Zu"): %s (probably PTY closed)",
84 pipe->fd, buff, bufsiz, strerror(_errno));
85 return 0;
86 } else {
87 Error4("read(%d, %p, "F_Zu"): %s",
88 pipe->fd, buff, bufsiz, strerror(_errno));
90 errno = _errno;
91 return -1;
93 break;
95 #if WITH_READLINE
96 case XIOREAD_READLINE:
97 if ((bytes = xioread_readline(pipe, buff, bufsiz)) < 0) {
98 return -1;
100 break;
101 #endif /* WITH_READLINE */
103 #if WITH_OPENSSL
104 case XIOREAD_OPENSSL:
105 /* this function prints its error messages */
106 if ((bytes = xioread_openssl(pipe, buff, bufsiz)) < 0) {
107 return -1;
109 break;
110 #endif /* WITH_OPENSSL */
112 #if _WITH_SOCKET
113 case XIOREAD_RECV:
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);
119 char infobuff[256];
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;
126 #endif
127 #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
128 msgh.msg_controllen = sizeof(ctrlbuff);
129 #endif
130 if (xiogetpacketsrc(pipe->fd, &msgh) < 0) {
131 return -1;
133 do {
134 bytes =
135 Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen);
136 } while (bytes < 0 && errno == EINTR);
137 if (bytes < 0) {
138 char infobuff[256];
139 _errno = errno;
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));
144 errno = _errno;
145 return -1;
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)
152 == 0) {
153 errno = EAGAIN; return -1;
156 #endif /* defined(PF_PACKET) && defined(PACKET_OUTGOING) */
158 Notice2("received packet with "F_Zu" bytes from %s",
159 bytes,
160 sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)));
161 if (bytes == 0) {
162 if (!pipe->para.socket.null_eof) {
163 errno = EAGAIN; return -1;
165 return bytes;
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;
175 #endif
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;
181 #if WITH_IP4
182 switch (pipe->peersa.soa.sa_family) {
183 case PF_INET:
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;
189 break;
191 #endif /* WITH_IP4 */
192 } else {
193 switch (pipe->peersa.soa.sa_family) {
194 #if 0
195 case PF_UNIX:
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;
201 break;
202 #endif
203 #if WITH_IP6
204 case PF_INET6:
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;
212 break;
213 #endif /* WITH_IP6 */
214 default:
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) {
224 int headlen;
225 #if WITH_IP4
226 case AF_INET:
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;
234 #endif
235 if (headlen > bytes) {
236 Warn1("xioread(%d, ...)/IP4: short packet", pipe->fd);
237 bytes = 0;
238 } else {
239 memmove(buff, ((char *)buff)+headlen, bytes-headlen);
240 bytes -= headlen;
243 break;
244 #endif
245 #if WITH_IP6
246 case AF_INET6:
247 /* does not seem to include header on Linux */
248 /* but sometimes on AIX */
249 break;
250 #endif
251 default:
252 /* do nothing, for now */
253 break;
255 if (pipe->dtype & XIOREAD_RECV_ONESHOT) {
256 #if 1
257 pipe->eof = 2;
258 #else
259 Shutdown(pipe->fd, SHUT_RD);
260 #endif
261 if (pipe->ppid > 0) {
262 Kill(pipe->ppid, SIGUSR1);
266 #if 0
267 if (fromlen != pipe->fd[0].salen) {
268 Debug("recvfrom(): wrong peer address length, ignoring packet");
269 continue;
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]);
299 continue;
301 #endif
302 #else /* !WITH_RAWIP */
303 Fatal("address requires raw sockets, but they are not compiled in");
304 return -1;
305 #endif /* !WITH_RAWIP || WITH_UDP || WITH_UNIX */
307 } else /* ~XIOREAD_RECV_FROM */ {
308 union sockaddr_union from; socklen_t fromlen = sizeof(from);
309 char infobuff[256];
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;
319 #endif
320 #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
321 msgh.msg_controllen = sizeof(ctrlbuff);
322 #endif
323 if (xiogetpacketsrc(pipe->fd, &msgh) < 0) {
324 return -1;
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)));
335 do {
336 bytes =
337 Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen);
338 } while (bytes < 0 && errno == EINTR);
339 if (bytes < 0) {
340 char infobuff[256];
341 _errno = errno;
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));
346 errno = _errno;
347 return -1;
349 Notice2("received packet with "F_Zu" bytes from %s",
350 bytes,
351 sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)));
352 if (bytes == 0) {
353 if (!pipe->para.socket.null_eof) {
354 errno = EAGAIN; return -1;
356 return bytes;
359 switch(from.soa.sa_family) {
360 int headlen;
361 #if WITH_IP4
362 case AF_INET:
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;
370 #endif
371 if (headlen > bytes) {
372 Warn1("xioread(%d, ...)/IP4: short packet", pipe->fd);
373 bytes = 0;
374 } else {
375 memmove(buff, ((char *)buff)+headlen, bytes-headlen);
376 bytes -= headlen;
379 break;
380 #endif
381 #if WITH_IP6
382 case AF_INET6: /* does not seem to include header... */
383 break;
384 #endif
385 default:
386 /* do nothing, for now */
387 break;
391 break;
392 #endif /* _WITH_SOCKET */
394 default:
395 Error("internal: undefined read operation");
396 errno = EINVAL; return -1;
398 pipe->actbytes -= bytes;
399 return 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) {
408 struct single *pipe;
410 if (file->tag == XIO_TAG_INVALID) {
411 Error1("xiopending(): invalid xiofile descriptor %p", file);
412 errno = EINVAL;
413 return -1;
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);
420 errno = EINVAL;
421 return -1;
423 } else {
424 pipe = &file->stream;
427 switch (pipe->dtype & XIODATA_READMASK) {
428 #if WITH_OPENSSL
429 case XIOREAD_OPENSSL:
430 return xiopending_openssl(pipe);
431 #endif /* WITH_OPENSSL */
432 default:
433 return 0;