OpenSSL options min-version, max-version
[socat.git] / xioread.c
blob24f3c887b34b5a94f23eae1640db662b49aa4499
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-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 ((from.ll.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 #if HAVE_STRUCT_IP
225 int headlen;
226 #endif /* HAVE_STRUCT_IP */
227 #if WITH_IP4
228 case AF_INET:
229 #if 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;
237 #endif
238 if (headlen > bytes) {
239 Warn1("xioread(%d, ...)/IP4: short packet", pipe->fd);
240 bytes = 0;
241 } else {
242 memmove(buff, ((char *)buff)+headlen, bytes-headlen);
243 bytes -= headlen;
246 #endif /* HAVE_STRUCT_IP */
247 break;
248 #endif
249 #if WITH_IP6
250 case AF_INET6:
251 /* does not seem to include header on Linux */
252 /* but sometimes on AIX */
253 break;
254 #endif
255 default:
256 /* do nothing, for now */
257 break;
259 if (pipe->dtype & XIOREAD_RECV_ONESHOT) {
260 #if 1
261 pipe->eof = 2;
262 #else
263 Shutdown(pipe->fd, SHUT_RD);
264 #endif
265 if (pipe->ppid > 0) {
266 Kill(pipe->ppid, SIGUSR1);
270 #if 0
271 if (fromlen != pipe->fd[0].salen) {
272 Debug("recvfrom(): wrong peer address length, ignoring packet");
273 continue;
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]);
303 continue;
305 #endif
306 #else /* !WITH_RAWIP */
307 Fatal("address requires raw sockets, but they are not compiled in");
308 return -1;
309 #endif /* !WITH_RAWIP || WITH_UDP || WITH_UNIX */
311 } else /* ~XIOREAD_RECV_FROM */ {
312 union sockaddr_union from; socklen_t fromlen = sizeof(from);
313 char infobuff[256];
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;
323 #endif
324 #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
325 msgh.msg_controllen = sizeof(ctrlbuff);
326 #endif
327 if (xiogetpacketsrc(pipe->fd, &msgh) < 0) {
328 return -1;
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)));
339 do {
340 bytes =
341 Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen);
342 } while (bytes < 0 && errno == EINTR);
343 if (bytes < 0) {
344 char infobuff[256];
345 _errno = errno;
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));
350 errno = _errno;
351 return -1;
353 Notice2("received packet with "F_Zu" bytes from %s",
354 bytes,
355 sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)));
356 if (bytes == 0) {
357 if (!pipe->para.socket.null_eof) {
358 errno = EAGAIN; return -1;
360 return bytes;
363 switch(from.soa.sa_family) {
364 #if HAVE_STRUCT_IP
365 int headlen;
366 #endif /* HAVE_STRUCT_IP */
367 #if WITH_IP4
368 case AF_INET:
369 #if 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;
377 #endif
378 if (headlen > bytes) {
379 Warn1("xioread(%d, ...)/IP4: short packet", pipe->fd);
380 bytes = 0;
381 } else {
382 memmove(buff, ((char *)buff)+headlen, bytes-headlen);
383 bytes -= headlen;
386 #endif /* HAVE_STRUCT_IP */
387 break;
388 #endif
389 #if WITH_IP6
390 case AF_INET6: /* does not seem to include header... */
391 break;
392 #endif
393 default:
394 /* do nothing, for now */
395 break;
399 break;
400 #endif /* _WITH_SOCKET */
402 default:
403 Error("internal: undefined read operation");
404 errno = EINVAL; return -1;
406 pipe->actbytes -= bytes;
407 return 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) {
416 struct single *pipe;
418 if (file->tag == XIO_TAG_INVALID) {
419 Error1("xiopending(): invalid xiofile descriptor %p", file);
420 errno = EINVAL;
421 return -1;
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);
428 errno = EINVAL;
429 return -1;
431 } else {
432 pipe = &file->stream;
435 switch (pipe->dtype & XIODATA_READMASK) {
436 #if WITH_OPENSSL
437 case XIOREAD_OPENSSL:
438 return xiopending_openssl(pipe);
439 #endif /* WITH_OPENSSL */
440 default:
441 return 0;