nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
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