nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* source: xioread.c */ |
2 | /* Copyright Gerhard Rieger 2001-2012 */ |
||
3 | /* Published under the GNU General Public License V.2, see file COPYING */ |
||
4 | |||
5 | /* this is the source of the extended read function */ |
||
6 | |||
7 | #include "xiosysincludes.h" |
||
8 | #include "xioopen.h" |
||
9 | |||
10 | #include "xio-termios.h" |
||
11 | #include "xio-socket.h" |
||
12 | #include "xio-test.h" |
||
13 | #include "xio-readline.h" |
||
14 | #include "xio-openssl.h" |
||
15 | |||
16 | |||
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 fd; |
||
26 | int _errno; |
||
27 | |||
28 | if (file->tag == XIO_TAG_INVALID) { |
||
29 | Error1("xioread(): invalid xiofile descriptor %p", file); |
||
30 | errno = EINVAL; |
||
31 | return -1; |
||
32 | } |
||
33 | |||
34 | if (file->tag == XIO_TAG_DUAL) { |
||
35 | pipe = file->dual.stream[0]; |
||
36 | if (pipe->tag == XIO_TAG_INVALID) { |
||
37 | Error1("xioread(): invalid xiofile sub descriptor %p[0]", file); |
||
38 | errno = EINVAL; |
||
39 | return -1; |
||
40 | } |
||
41 | } else { |
||
42 | pipe = &file->stream; |
||
43 | } |
||
44 | |||
45 | if (pipe->readbytes) { |
||
46 | if (pipe->actbytes == 0) { |
||
47 | return 0; /* EOF by count */ |
||
48 | } |
||
49 | |||
50 | if (pipe->actbytes < bufsiz) { |
||
51 | bufsiz = pipe->actbytes; |
||
52 | } |
||
53 | } |
||
54 | |||
55 | fd = XIO_GETRDFD(file); |
||
56 | |||
57 | switch (pipe->dtype & XIODATA_READMASK) { |
||
58 | case XIOREAD_STREAM: |
||
59 | do { |
||
60 | bytes = Read(fd, buff, bufsiz); |
||
61 | } while (bytes < 0 && errno == EINTR); |
||
62 | if (bytes < 0) { |
||
63 | _errno = errno; |
||
64 | switch (_errno) { |
||
65 | #if 1 |
||
66 | case EPIPE: case ECONNRESET: |
||
67 | Warn4("read(%d, %p, "F_Zu"): %s", |
||
68 | fd, buff, bufsiz, strerror(_errno)); |
||
69 | break; |
||
70 | #endif |
||
71 | default: |
||
72 | Error4("read(%d, %p, "F_Zu"): %s", |
||
73 | fd, buff, bufsiz, strerror(_errno)); |
||
74 | } |
||
75 | return -1; |
||
76 | } |
||
77 | break; |
||
78 | |||
79 | case XIODATA_PTY: |
||
80 | do { |
||
81 | bytes = Read(fd, buff, bufsiz); |
||
82 | } while (bytes < 0 && errno == EINTR); |
||
83 | if (bytes < 0) { |
||
84 | _errno = errno; |
||
85 | if (_errno == EIO) { |
||
86 | Notice4("read(%d, %p, "F_Zu"): %s (probably PTY closed)", |
||
87 | fd, buff, bufsiz, strerror(_errno)); |
||
88 | return 0; |
||
89 | } else { |
||
90 | Error4("read(%d, %p, "F_Zu"): %s", |
||
91 | fd, buff, bufsiz, strerror(_errno)); |
||
92 | } |
||
93 | errno = _errno; |
||
94 | return -1; |
||
95 | } |
||
96 | break; |
||
97 | |||
98 | case XIOREAD_PTY: |
||
99 | do { |
||
100 | bytes = Read(fd, buff, bufsiz); |
||
101 | } while (bytes < 0 && errno == EINTR); |
||
102 | if (bytes < 0) { |
||
103 | _errno = errno; |
||
104 | if (_errno == EIO) { |
||
105 | Notice4("read(%d, %p, "F_Zu"): %s (probably PTY closed)", |
||
106 | fd, buff, bufsiz, strerror(_errno)); |
||
107 | return 0; |
||
108 | } else { |
||
109 | Error4("read(%d, %p, "F_Zu"): %s", |
||
110 | fd, buff, bufsiz, strerror(_errno)); |
||
111 | } |
||
112 | errno = _errno; |
||
113 | return -1; |
||
114 | } |
||
115 | break; |
||
116 | |||
117 | #if WITH_READLINE |
||
118 | case XIOREAD_READLINE: |
||
119 | if ((bytes = xioread_readline(pipe, buff, bufsiz)) < 0) { |
||
120 | return -1; |
||
121 | } |
||
122 | break; |
||
123 | #endif /* WITH_READLINE */ |
||
124 | |||
125 | #if WITH_TEST |
||
126 | case XIOREAD_TEST: |
||
127 | /* this function prints its error messages */ |
||
128 | if ((bytes = xioread_test(pipe, buff, bufsiz)) < 0) { |
||
129 | return -1; |
||
130 | } |
||
131 | break; |
||
132 | #endif /* WITH_TEST */ |
||
133 | |||
134 | #if WITH_OPENSSL |
||
135 | case XIOREAD_OPENSSL: |
||
136 | /* this function prints its error messages */ |
||
137 | if ((bytes = xioread_openssl(pipe, buff, bufsiz)) < 0) { |
||
138 | return -1; |
||
139 | } |
||
140 | break; |
||
141 | #endif /* WITH_OPENSSL */ |
||
142 | |||
143 | #if _WITH_SOCKET |
||
144 | case XIOREAD_RECV: |
||
145 | if (pipe->dtype & XIOREAD_RECV_FROM) { |
||
146 | #if WITH_RAWIP || WITH_UDP || WITH_UNIX |
||
147 | struct msghdr msgh = {0}; |
||
148 | union sockaddr_union from = {{0}}; |
||
149 | socklen_t fromlen = sizeof(from); |
||
150 | char infobuff[256]; |
||
151 | char ctrlbuff[1024]; /* ancillary messages */ |
||
152 | |||
153 | msgh.msg_name = &from; |
||
154 | msgh.msg_namelen = fromlen; |
||
155 | #if HAVE_STRUCT_MSGHDR_MSGCONTROL |
||
156 | msgh.msg_control = ctrlbuff; |
||
157 | #endif |
||
158 | #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN |
||
159 | msgh.msg_controllen = sizeof(ctrlbuff); |
||
160 | #endif |
||
161 | if (xiogetpacketsrc(pipe->rfd, &msgh) < 0) { |
||
162 | return -1; |
||
163 | } |
||
164 | do { |
||
165 | bytes = Recvfrom(fd, buff, bufsiz, 0, &from.soa, &fromlen); |
||
166 | } while (bytes < 0 && errno == EINTR); |
||
167 | if (bytes < 0) { |
||
168 | char infobuff[256]; |
||
169 | _errno = errno; |
||
170 | Error6("recvfrom(%d, %p, "F_Zu", 0, %s, {"F_socklen"}): %s", |
||
171 | fd, buff, bufsiz, |
||
172 | sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)), |
||
173 | fromlen, strerror(errno)); |
||
174 | errno = _errno; |
||
175 | return -1; |
||
176 | } |
||
177 | /* on packet type we also receive outgoing packets, this is not desired |
||
178 | */ |
||
179 | #if defined(PF_PACKET) && defined(PACKET_OUTGOING) |
||
180 | if (from.soa.sa_family == PF_PACKET) { |
||
181 | if ((from.ll.sll_pkttype & PACKET_OUTGOING) |
||
182 | == 0) { |
||
183 | errno = EAGAIN; return -1; |
||
184 | } |
||
185 | } |
||
186 | #endif /* defined(PF_PACKET) && defined(PACKET_OUTGOING) */ |
||
187 | |||
188 | Notice2("received packet with "F_Zu" bytes from %s", |
||
189 | bytes, |
||
190 | sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff))); |
||
191 | if (bytes == 0) { |
||
192 | if (!pipe->para.socket.null_eof) { |
||
193 | errno = EAGAIN; return -1; |
||
194 | } |
||
195 | return bytes; |
||
196 | } |
||
197 | |||
198 | if (pipe->peersa.soa.sa_family != PF_UNSPEC) { |
||
199 | /* a peer address is registered, so we need to check if it matches */ |
||
200 | #if 0 /* with UNIX sockets we find inconsistent lengths */ |
||
201 | if (fromlen != pipe->salen) { |
||
202 | Info("recvfrom(): wrong peer address length, ignoring packet"); |
||
203 | errno = EAGAIN; return -1; |
||
204 | } |
||
205 | #endif |
||
206 | if (pipe->dtype & XIOREAD_RECV_SKIPIP) { |
||
207 | if (pipe->peersa.soa.sa_family != from.soa.sa_family) { |
||
208 | Info("recvfrom(): wrong peer protocol, ignoring packet"); |
||
209 | errno = EAGAIN; return -1; |
||
210 | } |
||
211 | #if WITH_IP4 |
||
212 | switch (pipe->peersa.soa.sa_family) { |
||
213 | case PF_INET: |
||
214 | if (pipe->peersa.ip4.sin_addr.s_addr != |
||
215 | from.ip4.sin_addr.s_addr) { |
||
216 | Info("recvfrom(): wrong peer address, ignoring packet"); |
||
217 | errno = EAGAIN; return -1; |
||
218 | } |
||
219 | break; |
||
220 | } |
||
221 | #endif /* WITH_IP4 */ |
||
222 | } else { |
||
223 | switch (pipe->peersa.soa.sa_family) { |
||
224 | #if 0 |
||
225 | case PF_UNIX: |
||
226 | if (strncmp(pipe->peersa.un.sun_path, from.un.sun_path, |
||
227 | sizeof(from.un.sun_path))) { |
||
228 | Info("recvfrom(): wrong peer address, ignoring packet"); |
||
229 | errno = EAGAIN; return -1; |
||
230 | } |
||
231 | break; |
||
232 | #endif |
||
233 | #if WITH_IP6 |
||
234 | case PF_INET6: |
||
235 | /* e.g. Solaris recvfrom sets a __sin6_src_id component */ |
||
236 | if (memcmp(&from.ip6.sin6_addr, &pipe->peersa.ip6.sin6_addr, |
||
237 | sizeof(from.ip6.sin6_addr)) || |
||
238 | from.ip6.sin6_port != pipe->peersa.ip6.sin6_port) { |
||
239 | Info("recvfrom(): wrong peer address, ignoring packet"); |
||
240 | errno = EAGAIN; return -1; |
||
241 | } |
||
242 | break; |
||
243 | #endif /* WITH_IP6 */ |
||
244 | default: |
||
245 | if (memcmp(&from, &pipe->peersa, fromlen)) { |
||
246 | Info("recvfrom(): wrong peer address, ignoring packet"); |
||
247 | errno = EAGAIN; return -1; |
||
248 | } |
||
249 | } |
||
250 | } |
||
251 | } |
||
252 | |||
253 | switch(from.soa.sa_family) { |
||
254 | int headlen; |
||
255 | #if WITH_IP4 |
||
256 | case AF_INET: |
||
257 | if (pipe->dtype & XIOREAD_RECV_SKIPIP) { |
||
258 | /* IP4 raw sockets include the header when passing a packet to the |
||
259 | application - we don't need it here. */ |
||
260 | #if HAVE_STRUCT_IP_IP_HL |
||
261 | headlen = 4*((struct ip *)buff)->ip_hl; |
||
262 | #else /* happened on Tru64 */ |
||
263 | headlen = 4*((struct ip *)buff)->ip_vhl; |
||
264 | #endif |
||
265 | if (headlen > bytes) { |
||
266 | Warn1("xioread(%d, ...)/IP4: short packet", fd); |
||
267 | bytes = 0; |
||
268 | } else { |
||
269 | memmove(buff, ((char *)buff)+headlen, bytes-headlen); |
||
270 | bytes -= headlen; |
||
271 | } |
||
272 | } |
||
273 | break; |
||
274 | #endif |
||
275 | #if WITH_IP6 |
||
276 | case AF_INET6: |
||
277 | /* does not seem to include header on Linux */ |
||
278 | /* but sometimes on AIX */ |
||
279 | break; |
||
280 | #endif |
||
281 | default: |
||
282 | /* do nothing, for now */ |
||
283 | break; |
||
284 | } |
||
285 | if (pipe->dtype & XIOREAD_RECV_ONESHOT) { |
||
286 | #if 1 |
||
287 | pipe->eof = 2; |
||
288 | #else |
||
289 | Shutdown(pipe->fd, SHUT_RD); |
||
290 | #endif |
||
291 | if (pipe->ppid > 0) { |
||
292 | Kill(pipe->ppid, SIGUSR1); |
||
293 | } |
||
294 | } |
||
295 | |||
296 | #if 0 |
||
297 | if (fromlen != pipe->fd[0].salen) { |
||
298 | Debug("recvfrom(): wrong peer address length, ignoring packet"); |
||
299 | continue; |
||
300 | } |
||
301 | if (memcmp(&from, &pipe->fd[0].peersa.sa, fromlen)) { |
||
302 | Debug("recvfrom(): other peer address, ignoring packet"); |
||
303 | Debug16("peer: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", |
||
304 | pipe->fd[0].peersa.space[0], |
||
305 | pipe->fd[0].peersa.space[1], |
||
306 | pipe->fd[0].peersa.space[2], |
||
307 | pipe->fd[0].peersa.space[3], |
||
308 | pipe->fd[0].peersa.space[4], |
||
309 | pipe->fd[0].peersa.space[5], |
||
310 | pipe->fd[0].peersa.space[6], |
||
311 | pipe->fd[0].peersa.space[7], |
||
312 | pipe->fd[0].peersa.space[8], |
||
313 | pipe->fd[0].peersa.space[9], |
||
314 | pipe->fd[0].peersa.space[10], |
||
315 | pipe->fd[0].peersa.space[11], |
||
316 | pipe->fd[0].peersa.space[12], |
||
317 | pipe->fd[0].peersa.space[13], |
||
318 | pipe->fd[0].peersa.space[14], |
||
319 | pipe->fd[0].peersa.space[15]); |
||
320 | Debug16("from: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", |
||
321 | from.space[0], from.space[1], |
||
322 | from.space[2], from.space[3], |
||
323 | from.space[4], from.space[5], |
||
324 | from.space[6], from.space[7], |
||
325 | from.space[8], from.space[9], |
||
326 | from.space[10], from.space[11], |
||
327 | from.space[12], from.space[13], |
||
328 | from.space[14], from.space[15]); |
||
329 | continue; |
||
330 | } |
||
331 | #endif |
||
332 | #else /* !WITH_RAWIP */ |
||
333 | Fatal("address requires raw sockets, but they are not compiled in"); |
||
334 | return -1; |
||
335 | #endif /* !WITH_RAWIP || WITH_UDP || WITH_UNIX */ |
||
336 | |||
337 | } else /* ~XIOREAD_RECV_FROM */ { |
||
338 | union sockaddr_union from; socklen_t fromlen = sizeof(from); |
||
339 | char infobuff[256]; |
||
340 | struct msghdr msgh = {0}; |
||
341 | char ctrlbuff[1024]; /* ancillary messages */ |
||
342 | |||
343 | socket_init(pipe->para.socket.la.soa.sa_family, &from); |
||
344 | /* get source address */ |
||
345 | msgh.msg_name = &from; |
||
346 | msgh.msg_namelen = fromlen; |
||
347 | #if HAVE_STRUCT_MSGHDR_MSGCONTROL |
||
348 | msgh.msg_control = ctrlbuff; |
||
349 | #endif |
||
350 | #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN |
||
351 | msgh.msg_controllen = sizeof(ctrlbuff); |
||
352 | #endif |
||
353 | if (xiogetpacketsrc(pipe->rfd, &msgh) < 0) { |
||
354 | return -1; |
||
355 | } |
||
356 | xiodopacketinfo(&msgh, true, false); |
||
357 | if (xiocheckpeer(pipe, &from, &pipe->para.socket.la) < 0) { |
||
358 | Recvfrom(fd, buff, bufsiz, 0, &from.soa, &fromlen); /* drop */ |
||
359 | errno = EAGAIN; return -1; |
||
360 | } |
||
361 | Info1("permitting packet from %s", |
||
362 | sockaddr_info((struct sockaddr *)&from, fromlen, |
||
363 | infobuff, sizeof(infobuff))); |
||
364 | |||
365 | do { |
||
366 | bytes = |
||
367 | Recvfrom(fd, buff, bufsiz, 0, &from.soa, &fromlen); |
||
368 | } while (bytes < 0 && errno == EINTR); |
||
369 | if (bytes < 0) { |
||
370 | char infobuff[256]; |
||
371 | _errno = errno; |
||
372 | Error6("recvfrom(%d, %p, "F_Zu", 0, %s, "F_socklen"): %s", |
||
373 | fd, buff, bufsiz, |
||
374 | sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)), |
||
375 | fromlen, strerror(errno)); |
||
376 | errno = _errno; |
||
377 | return -1; |
||
378 | } |
||
379 | Notice2("received packet with "F_Zu" bytes from %s", |
||
380 | bytes, |
||
381 | sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff))); |
||
382 | if (bytes == 0) { |
||
383 | if (!pipe->para.socket.null_eof) { |
||
384 | errno = EAGAIN; return -1; |
||
385 | } |
||
386 | return bytes; |
||
387 | } |
||
388 | |||
389 | switch(from.soa.sa_family) { |
||
390 | int headlen; |
||
391 | #if WITH_IP4 |
||
392 | case AF_INET: |
||
393 | if (pipe->dtype & XIOREAD_RECV_SKIPIP) { |
||
394 | /* IP4 raw sockets include the header when passing a packet to the |
||
395 | application - we don't need it here. */ |
||
396 | #if HAVE_STRUCT_IP_IP_HL |
||
397 | headlen = 4*((struct ip *)buff)->ip_hl; |
||
398 | #else /* happened on Tru64 */ |
||
399 | headlen = 4*((struct ip *)buff)->ip_vhl; |
||
400 | #endif |
||
401 | if (headlen > bytes) { |
||
402 | Warn1("xioread(%d, ...)/IP4: short packet", fd); |
||
403 | bytes = 0; |
||
404 | } else { |
||
405 | memmove(buff, ((char *)buff)+headlen, bytes-headlen); |
||
406 | bytes -= headlen; |
||
407 | } |
||
408 | } |
||
409 | break; |
||
410 | #endif |
||
411 | #if WITH_IP6 |
||
412 | case AF_INET6: /* does not seem to include header... */ |
||
413 | break; |
||
414 | #endif |
||
415 | default: |
||
416 | /* do nothing, for now */ |
||
417 | break; |
||
418 | } |
||
419 | |||
420 | } |
||
421 | break; |
||
422 | #endif /* _WITH_SOCKET */ |
||
423 | |||
424 | default: |
||
425 | Error("internal: undefined read operation"); |
||
426 | errno = EINVAL; return -1; |
||
427 | } |
||
428 | pipe->actbytes -= bytes; |
||
429 | return bytes; |
||
430 | } |
||
431 | |||
432 | |||
433 | /* this function is intended only for some special address types where the |
||
434 | select()/poll() calls cannot strictly determine if (more) read data is |
||
435 | available. currently this is for the OpenSSL based addresses. |
||
436 | */ |
||
437 | ssize_t xiopending(xiofile_t *file) { |
||
438 | struct single *pipe; |
||
439 | |||
440 | if (file->tag == XIO_TAG_INVALID) { |
||
441 | Error1("xiopending(): invalid xiofile descriptor %p", file); |
||
442 | errno = EINVAL; |
||
443 | return -1; |
||
444 | } |
||
445 | |||
446 | if (file->tag == XIO_TAG_DUAL) { |
||
447 | pipe = file->dual.stream[0]; |
||
448 | if (pipe->tag == XIO_TAG_INVALID) { |
||
449 | Error1("xiopending(): invalid xiofile sub descriptor %p[0]", file); |
||
450 | errno = EINVAL; |
||
451 | return -1; |
||
452 | } |
||
453 | } else { |
||
454 | pipe = &file->stream; |
||
455 | } |
||
456 | |||
457 | switch (pipe->dtype & XIODATA_READMASK) { |
||
458 | #if WITH_OPENSSL |
||
459 | case XIOREAD_OPENSSL: |
||
460 | return xiopending_openssl(pipe); |
||
461 | #endif /* WITH_OPENSSL */ |
||
462 | default: |
||
463 | return 0; |
||
464 | } |
||
465 | } |
||
466 |